chaining comparisons

Ask a Question related to Ruby, Design and Development.

  1. #1

    Default chaining comparisons

    When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    and get "true". I just realized that you can't do that in Ruby. Is
    there a reason why? Is it good? I know I can use "between", but
    still...

    -Kurt

    Kurt M. Dresner Guest

  2. Similar Questions and Discussions

    1. Chaining live video stream
      :beer; Hello : I have a problem of server side "Stream class" and rebublish live video stream. In brief, I assume the live video stream can...
    2. Chaining streams between 2 media server
      Hi i'm trying to setup a stream chaining between 2 flash media servers. Basically I have an swf that streams my camera to FS Server 1. In FS...
    3. Is it possible to predetermine the order of HttpModule calls or implement filter chaining in ASP.Net
      Hi people, I am wondering if it is possible to pretermine the order of the HttpModules being executed. If not, how can one implement interceptor...
    4. comparisons and depth
      sorry to post two questions in one day, but i have run into a second problem. i have a looping movie clip which changes _y position randomly with...
    5. chaining of -> operator
      With total disregard for any kind of safety measures Chris Laird <chris@SPAM.pocketGUARDfluff.net> leapt forth and uttered: PHP4 doesn't...
  3. #2

    Default Re: chaining comparisons

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    I don't know if there's a good reason for it, but I think it'd be cool if
    Ruby had it.

    On Sat, Jul 19, 2003 at 02:58:51PM +0900, Kurt M. Dresner wrote:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    > and get "true". I just realized that you can't do that in Ruby. Is
    > there a reason why? Is it good? I know I can use "between", but
    > still...
    >
    > -Kurt
    >
    - --
    Daniel Carrera | OpenPGP fingerprint:
    Mathematics Dept. | 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
    UMD, College Park | [url]http://www.math.umd.edu/~dcarrera/pgp.html[/url]
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.2 (SunOS)

    iD8DBQE/GN7LnxE8DWHf+OcRAthlAJ4zuAlY0EjdVHEwFLohg/G8OwOsXwCgq63a
    blsFqUDYa9irZbjUPNyEdDI=
    =bI3R
    -----END PGP SIGNATURE-----

    Daniel Carrera Guest

  4. #3

    Default Re: chaining comparisons

    In article <20030719060149.GA2247@math.umd.edu>,
    Daniel Carrera <dcarrera@math.umd.edu> wrote:
    >-----BEGIN PGP SIGNED MESSAGE-----
    >Hash: SHA1
    >
    >I don't know if there's a good reason for it, but I think it'd be cool if
    >Ruby had it.
    >
    >On Sat, Jul 19, 2003 at 02:58:51PM +0900, Kurt M. Dresner wrote:
    >> When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    >> and get "true". I just realized that you can't do that in Ruby. Is
    >> there a reason why? Is it good? I know I can use "between", but
    >> still...
    >>

    I can see how it would be cool, however:

    1 < 2 #this gives a value of true
    1 < 2 < 3 #this calls the '<(3)' method on true

    It essentially looks like:
    (true) < 3

    Which is meaningless.

    to do this you've got to somehow change the parser so that for the special cases of
    <,>,<=,>= you instead call the method on the middle value in the chain of thee values.
    Or you've got to somehow make '1 < 2' return 2 instead of/or in addition to true.
    Seems problematic and could very likely break things.

    2.between?(1,3)
    May not look as pretty, but works fine without potential parser headaches.

    Phil
    Phil Tomson Guest

  5. #4

    Default Re: chaining comparisons

    On Saturday, July 19, 2003, 3:58:51 PM, Kurt wrote:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    > and get "true". I just realized that you can't do that in Ruby. Is
    > there a reason why? Is it good? I know I can use "between", but
    > still...
    I agree it would be cool, but it's pretty clear why Ruby doens't
    support it:

    2 < 3 == true
    1 < true == error
    therefore 1 < 2 < 3 == error

    Ruby is a very expression-oriented language, and derives its strength
    from conceptual purity. If an expression evaluated to X in some
    circumstances and Y in others, a small part of Ruby would be lost.

    Gavin


    Gavin Sinclair Guest

  6. #5

    Default Re: chaining comparisons

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    On Sat, Jul 19, 2003 at 03:47:38PM +0900, Gavin Sinclair wrote:
    > I agree it would be cool, but it's pretty clear why Ruby doens't
    > support it:
    >
    > 2 < 3 == true
    > 1 < true == error
    > therefore 1 < 2 < 3 == error
    >
    > Ruby is a very expression-oriented language, and derives its strength
    > from conceptual purity. If an expression evaluated to X in some
    > circumstances and Y in others, a small part of Ruby would be lost.
    I realize that this is a dumb question, but what is an expression-oriented
    language?

    Can you contrast Ruby with a language that is not expression-oriented?


    - --
    Daniel Carrera | OpenPGP fingerprint:
    Mathematics Dept. | 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
    UMD, College Park | [url]http://www.math.umd.edu/~dcarrera/pgp.html[/url]
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.2 (SunOS)

    iD8DBQE/GOp2nxE8DWHf+OcRAjzWAJ0c6ZKLbvxueD6lSX4T7dWBhS0eMQ CeJA54
    IFr+5WRHMr+tDTeIz+YDNwo=
    =Y+Y0
    -----END PGP SIGNATURE-----

    Daniel Carrera Guest

  7. #6

    Default Re: chaining comparisons


    On Saturday, July 19, 2003, at 01:58 AM, Kurt M. Dresner wrote:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    > and get "true". I just realized that you can't do that in Ruby. Is
    > there a reason why? Is it good? I know I can use "between", but
    > still...
    >
    > -Kurt
    While I was writing this message, Phil responded with some similar
    thoughts, but I will post anyway, with apologies for the areas of
    duplication.

    A few of thoughts:

    1. It seems that in python '1 < 2 < 3' is sugar for '1 is less than 2
    and 2 is less than 3'.

    2. How does python handle '1 < 2 < 3 < 4'? How does python handle '1 <
    2 or 5 < 4'?

    2. In Ruby 1 < 2 is a representation of the Fixnum object 1 calling the
    '<' method with argument Fixnum object 2. The object returned is 'true'
    (an object of the TrueClass). In the expression '1 < 2 < 3', the 'true'
    object calls the '<' method with argument '3', an a no method error is
    raised.

    3. You can write the expression in Ruby as '1 < 2 and 2 < 3'.

    4. You could also modify the '<' method to return the value of the
    argument given if it evaluates to 'true' -- however, you would have to
    parse the output so that the last comparison returns 'true' and not the
    last argument. The following just modifies the return value of '<' and
    does not handle the problem of the method chain now returning the last
    argument:

    class Fixnum
    alias old_less_than <
    def < (arg)
    if self.old_less_than(arg)
    return arg
    end
    end
    end

    1 < 2 < 3 => 3

    5. You could also parse input so that '1 < 2 < 3' is translated to '1 <
    2 and 2 < 3'. I haven't thought about how to do this from within Ruby.

    6. I prefer the explicit '1 < 2 and 2 < 3'.

    Regards,

    Mark


    Mark Wilson Guest

  8. #7

    Default Re: chaining comparisons

    On Sat, 19 Jul 2003 15:58:51 +0900, Kurt M. Dresner wrote:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    > and get "true". I just realized that you can't do that in Ruby. Is
    > there a reason why? Is it good? I know I can use "between", but
    > still...

    You can do this:

    if [1, 2, 3].ordered?
    puts "ok"
    end


    It will require that you extend the Array class yourself, like this:
    > expand -t4 b.rb
    class Array
    def ordered?
    return true if self.empty?
    a = self.first
    self[1..-1].each { |b|
    return false if a > b
    a = b
    }
    true
    end
    end

    p [].ordered? #=> true
    p [2].ordered? #=> true
    p [-1, 2, 3, 5].ordered? #=> true
    p [17, 13, 11].ordered? #=> false
    p [1, -1, 1, 0].ordered? #=> false
    >
    The output is:
    > ruby b.rb
    true
    true
    true
    false
    false
    >

    --
    Simon Strandgaard


    Simon Strandgaard Guest

  9. #8

    Default Re: chaining comparisons

    Gavin Sinclair <gsinclair@soyabean.com.au> wrote:
    > On Saturday, July 19, 2003, 3:58:51 PM, Kurt wrote:
    >
    >> When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    >> and get "true". I just realized that you can't do that in Ruby. Is
    >> there a reason why? Is it good? I know I can use "between", but
    >> still...
    >
    > I agree it would be cool, but it's pretty clear why Ruby doens't
    > support it:
    >
    > 2 < 3 == true
    > 1 < true == error
    > therefore 1 < 2 < 3 == error
    >
    > Ruby is a very expression-oriented language, and derives its strength
    > from conceptual purity. If an expression evaluated to X in some
    > circumstances and Y in others, a small part of Ruby would be lost.
    One way to do it would be to have 'if' call to_boolean on its argument,
    and have < return an object that carried some state around.

    martin
    Martin DeMello Guest

  10. #9

    Default Re: chaining comparisons

    On Saturday, July 19, 2003, 4:51:42 PM, Daniel wrote:
    > On Sat, Jul 19, 2003 at 03:47:38PM +0900, Gavin Sinclair wrote:
    >> I agree it would be cool, but it's pretty clear why Ruby doens't
    >> support it:
    >>
    >> 2 < 3 == true
    >> 1 < true == error
    >> therefore 1 < 2 < 3 == error
    >>
    >> Ruby is a very expression-oriented language, and derives its strength
    >> from conceptual purity. If an expression evaluated to X in some
    >> circumstances and Y in others, a small part of Ruby would be lost.
    > I realize that this is a dumb question, but what is an expression-oriented
    > language?
    Don't worry, I've never seen/heard that assortment of words either.
    What I mean is that Ruby gives primacy to expressions (as opposed to
    statements). For instance (not tested):

    extractor =
    case opt
    when "-r" then ReceiptExtractor
    when "-t" then TransactionExtractor
    end.new(filename)

    Every chunk of code has a "return value" that can be used to build
    larger expressions.
    > Can you contrast Ruby with a language that is not expression-oriented?
    Try the concepts in the above code in just about any language :)

    Many/most languages enforce a difference between "statement" and
    "expression". Pascal is an example.

    Gavin


    Gavin Sinclair Guest

  11. #10

    Default Re: chaining comparisons

    On Sat, Jul 19, 2003 at 02:58:51PM +0900, Kurt M. Dresner wrote:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    > and get "true". I just realized that you can't do that in Ruby. Is
    > there a reason why? Is it good? I know I can use "between", but
    > still...
    You can also use range objects for a clean alternative to a <= b <= c :

    x = 2 # or 1 or 3
    if (1..3) === x
    puts "It's in the range"
    end

    The strange 'backwards' ordering is to support case statements, which make
    it look much clearer:

    case x
    when (1..3)
    puts "It's in the lower range"
    when (4..6)
    puts "It's in the upper range"
    else
    puts "It's out of range"
    end

    In the above, 3.5 is also 'out of range'. But the three-dot form of range
    supports a <= b < c

    puts "nope" if (1...3) === 3.0 # false
    puts "yep " if (1...3) === 2.99 # true

    case x
    when (1...4) # 1 to 3.999
    when (4...7) # 4 to 6.999
    when (7...10) # 7 to 9.999
    end

    Cheers,

    Brian.

    Brian Candler Guest

  12. #11

    Default Re: chaining comparisons

    On Sat, 19 Jul 2003 18:41:33 +0900, Brian Candler wrote:
    > On Sat, Jul 19, 2003 at 05:08:03PM +0900, Simon Strandgaard wrote:
    >> You can do this:
    >>
    >> if [1, 2, 3].ordered?
    >> puts "ok"
    >> end
    >>
    >>
    >> It will require that you extend the Array class yourself, like this:
    >>
    >> > expand -t4 b.rb
    >> class Array
    >> def ordered?
    > self == sort
    > end
    > end
    >
    > (I'm a lazy typist :-)
    Work smarter, Not harder.
    I know sort, But this solution didn't come to mind.

    > Both versions generate a temporary copy of the array, e.g. self[1..-1] does
    > that too. But you can avoid it:
    Yes. Avoiding temporary copy were my goal when I started writing it.
    As you can see I apparently forgot it in the hurry :-)


    [snip enum#ordered?]
    > You can then check whether all the lines in a file are ordered, for example,
    > without reading it into memory. (I am a big fan of Enumerable :-)
    Enum is Nice.

    Some more thoughts on #ordered?

    Supplying an operator, could be useful?

    [3, 2, 1].ordered? :> #=> true
    [2, 2, 2].ordered? :> #=> false
    [2, 2, 2].ordered? :>= #=> true


    Supplying an block could also be useful?

    [2, 2, 2].ordered? { |a, b| (((a-b) ^ (b-a)) % 3) == 0 }
    #=> true

    [1, 2, 3].ordered? { |a, b| (((a-b) ^ (b-a)) % 3) == 0 }
    #=> false

    --
    Simon Strandgaard
    Simon Strandgaard Guest

  13. #12

    Default Re: chaining comparisons

    Simon Strandgaard <0bz63fz3m1qt3001@sneakemail.com> wrote:
    > class Array
    > def ordered?
    > return true if self.empty?
    > a = self.first
    > self[1..-1].each { |b|
    > return false if a > b
    > a = b
    > }
    > true
    > end
    > end
    This (anti?)pattern always bothers me - surely a 2-element sliding
    window is a common enough pattern that we should capture it once and for
    all in Enumerable.

    It's in Joel VanderWerf's excellent EnumerableTools, but people tend not
    to include external packages when writing quick scripts. For instance,
    the current script would simply be

    class Array
    def ordered?
    each_cluster(2){|i,j| return false if i > j}
    true
    end
    end

    Personally, I'd like to see an each and an eachn, both taking block
    arity into account:

    a = *(1..6)
    a.eachn {|x,y| p [x,y]} #=> [1,2] [3,4] [5,6]
    a.each {|x,y| p [x,y]} #=> [1,2] [2,3] [3,4] [4,5] [5,6]

    This would also preserve the semantics of 'each' only consuming one
    element per iteration.

    martin
    Martin DeMello Guest

  14. #13

    Default Re: chaining comparisons

    Hi --

    On Sat, 19 Jul 2003, Kurt M. Dresner wrote:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    > and get "true". I just realized that you can't do that in Ruby. Is
    > there a reason why? Is it good? I know I can use "between", but
    > still...
    Matz's reason, in rejecting this in RCR form, was, "It's hard to
    define semantics of chain comparison in "OO" way. Use ranges instead."
    (See <http://www.rubygarden.org/article.php?sid=286>.)


    David

    --
    David Alan Black
    home: [email]dblack@superlink.net[/email]
    work: [email]blackdav@shu.edu[/email]
    Web: [url]http://pirate.shu.edu/~blackdav[/url]


    dblack@superlink.net Guest

  15. #14

    Default Re: chaining comparisons

    Hi,

    In message "Re: chaining comparisons"
    on 03/07/19, news_chr <swap@gmx.net> writes:

    |class Fixnum
    | alias __lt <
    | alias __le <=
    | alias __gt >
    | alias __ge >=
    | def <(r)
    | __lt(r) ? r : nil
    | end
    | def <(r)
    | __lt(r) ? r : nil
    | end
    | def <=(r)
    | __le(r) ? r : nil
    | end
    | def >(r)
    | __gt(r) ? r : nil
    | end
    | def >=(r)
    | __ge(r) ? r : nil
    | end
    |end
    |
    |
    |class NilClass
    | def <(r) self end
    | def <=(r) self end
    | def >(r) self end
    | def >=(r) self end
    |end
    |
    |
    |p ((4 < 5) < 6) < 7 # 7
    |
    |p ((4 < 5) < 5) < 7 # nil
    |
    |p ((4 < 5) >= 5) < 7 # 7
    |----
    |
    |Personally I wouldn't mind such a semantic but it is
    |probably too wired for general consumption ...

    They used to work like this long time ago. But I felt the semantic
    was too weird.

    matz.

    Yukihiro Matsumoto Guest

  16. #15

    Default Re: chaining comparisons

    On 19 Jul 2003 at 17:41, Brian Candler wrote:
    > Both versions generate a temporary copy of the array, e.g. self[1..-1] does
    > that too. But you can avoid it:
    >
    > module Enumerable
    > def ordered?
    > first = true
    > prev = nil
    > each do |item|
    > if first
    > first = false
    > else
    > return false if prev > item
    > end
    > prev = item
    > end
    > return true
    > end
    > end
    I'm not Dave Thomas :-) but you can also use inject here:

    module Enumerable
    def ordered?
    inject { | last, item | return false unless last < item; item }
    true
    end
    end

    Regards,
    Pit

    Pit Capitain Guest

  17. #16

    Default Re: chaining comparisons

    On Sat, Jul 19, 2003 at 11:23:04PM +0900, Pit Capitain wrote:
    > I'm not Dave Thomas :-) but you can also use inject here:
    >
    > module Enumerable
    > def ordered?
    > inject { | last, item | return false unless last < item; item }
    > true
    > end
    > end
    Which implementation of 'inject' are you using? The one in PragProg requires
    an initial value to be passed as a parameter.

    With an array of N elements you either need to do N-1 comparisons, or you
    need to start with a sentinel value which is guaranteed to be less than all
    other elements (nil and 0 both aren't suitable). So I don't see how the
    above works, but without its partner 'inject' implementation I can't comment
    further.

    Regards,

    Brian.

    Brian Candler Guest

  18. #17

    Default Re: chaining comparisons

    On 20 Jul 2003 at 0:10, Brian Candler wrote:
    > Which implementation of 'inject' are you using? The one in PragProg requires
    > an initial value to be passed as a parameter.
    It's Andy's Windows installer version:

    D:\Temp>ruby -v
    ruby 1.8.0 (2003-05-26) [i386-mswin32]


    And ri says about inject:

    D:\Temp>ri inject
    This is a test 'ri'. Please report errors and omissions
    on [url]http://www.rubygarden.org/ruby?RIOnePointEight[/url]

    ------------------------------------------------------
    Enumerable#inject
    enumObj.inject(initial) {| memo, obj | block } -> anObject
    enumObj.inject {| memo, obj | block } -> anObject
    ---------------------------------------------------------------------
    Combines the elements of enumObj by applying the block to an
    accumulator value (memo) and each element in turn. At each step,
    memo is set to the value returned by the block. The first form lets
    you supply an initial value for memo. The second form uses the
    first element of the collection as a the initial value (and skips
    that element while iterating).
    > With an array of N elements you either need to do N-1 comparisons,
    This is what the second form does.
    > or you
    > need to start with a sentinel value which is guaranteed to be less than all
    > other elements (nil and 0 both aren't suitable).
    This is what the first form would do.

    BTW, if you wanted to add the compare method as a parameter as
    someone else suggested, you could define

    module Enumerable
    def ordered?( compare_method = :< )
    inject { | last, item |
    return false unless last.send( compare_method, item )
    item
    }
    true
    end
    end

    and then call it like

    p [ 1, 2, 2 ].ordered? # => false
    p [ 1, 2, 2 ].ordered?( :<= ) # => true

    Isn't it fun to code in Ruby :< )

    Regards,
    Pit

    Pit Capitain Guest

  19. #18

    Default Re: chaining comparisons

    Saluton!

    * Kurt M. Dresner; 2003-07-19, 11:33 UTC:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 <
    > 3 and get "true". I just realized that you can't do that in Ruby.
    > Is there a reason why?
    a < b and b < c imply a < c. But what if you want to evaluate
    a < b > c? Which conditons do you require to be met?

    (1) a < b, b > c and a < c
    (2) a < b, b > c and a > c
    (3) a < b, b > c and nothing more

    Some examples:

    2 < 3 > 1 -> (2), (3)
    1 < 3 > 2 -> (1), (3)
    2 < 3 > 2 -> (3)

    It seems to be better *not* to use '<' and the like. Better use
    methods that can be applied to an arbitrary number of elements:

    def increasing(*list)
    return true if list.length < 2
    y = nil
    list.each {|x|
    return false unless y.nil? or y < x
    y = x
    }
    true
    end

    Gis,

    Josef 'Jupp' Schugt
    --
    N'attribuez jamais à la malice ce que l'incompétence explique !
    -- Napoléon

    Josef 'Jupp' Schugt Guest

  20. #19

    Default Re: chaining comparisons

    On Sat, 19 Jul 2003 14:58:51 +0900
    "Kurt M. Dresner" <kdresner@cs.utexas.edu> wrote:
    > When I learned python I was overjoyed that I could evaluate 1 < 2 < 3
    > and get "true". I just realized that you can't do that in Ruby. Is
    > there a reason why? Is it good? I know I can use "between", but
    > still...
    [url]http://www.rubygarden.org/article.php?sid=286[/url]

    So basically, it's because it's hard to implement, even more so because
    true/false/nil are singleton objects. (So you can't, for instance, save state
    in a particular instance of 'true', because there's only one.)

    Jason Creighton

    Jason Creighton Guest

  21. #20

    Default Re: chaining comparisons

    On Sun, 20 Jul 2003 00:10:25 +0900
    Brian Candler <B.Candler@pobox.com> wrote:
    > On Sat, Jul 19, 2003 at 11:23:04PM +0900, Pit Capitain wrote:
    > > I'm not Dave Thomas :-) but you can also use inject here:
    > >
    > > module Enumerable
    > > def ordered?
    > > inject { | last, item | return false unless last < item; item }
    > > true
    > > end
    > > end
    >
    > Which implementation of 'inject' are you using? The one in PragProg requires
    > an initial value to be passed as a parameter.
    The inject in 1.8 defaults its initial value to the first item in the collection.

    Jason Creighton
    Jason Creighton Guest

Posting Permissions

  • You may not post new threads
  • You may post replies
  • You may not post attachments
  • You may not edit your posts

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139