Forum: Ruby Method '!='

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Victor S. (Guest)
on 2006-05-26 09:27
(Received via mailing list)
Hello all.

I've tried something like this:

'a'.send('==', 'b') #it works, returns true

But

'a'.send('!=', 'b')

said to me:

tricks.rb:11:in `Kernel#send': undefined method `!=' for "a":String
(NoMethodError)

Where am I wrong?

V.
Justin C. (Guest)
on 2006-05-26 09:30
(Received via mailing list)
Victor S. wrote:
> said to me:
>
> tricks.rb:11:in `Kernel#send': undefined method `!=' for "a":String
> (NoMethodError)
>
> Where am I wrong?
>
> V.
>
>
>

a != b gets turned into !(a == b) or something like that.

So != isn't really a method - it's just syntax.

-Justin
Victor S. (Guest)
on 2006-05-26 09:30
(Received via mailing list)
> I've tried something like this:
>
> 'a'.send('==', 'b') #it works, returns true

Sorry. Return 'false', of couse.

V.
Victor S. (Guest)
on 2006-05-26 09:33
(Received via mailing list)
From: Justin C. [mailto:removed_email_address@domain.invalid]
Sent: Friday, May 26, 2006 8:28 AM
> >
> >
>
> a != b gets turned into !(a == b) or something like that.
>
> So != isn't really a method - it's just syntax.

It's intuitively understandable; but I feel myself very uncomfortable
when I
can *call*, but can't *send*. OK, would remember this one.

> -Justin

V.
Alder G. (Guest)
on 2006-05-26 09:45
(Received via mailing list)
On 5/26/06, Victor S. <removed_email_address@domain.invalid> wrote:
> From: Justin C. [mailto:removed_email_address@domain.invalid]
> Sent: Friday, May 26, 2006 8:28 AM
> ...
> It's intuitively understandable; but I feel myself very uncomfortable when I
> can *call*, but can't *send*. OK, would remember this one.
>
> > -Justin

You can't call:

irb(main):007:0> 'a'.!= 'b'
SyntaxError: compile error
(irb):7: parse error, unexpected tNEQ
'a'.!= 'b'
      ^

So it actually makes sense: you can't call, so you can't send.
Victor S. (Guest)
on 2006-05-26 09:52
(Received via mailing list)
From: Alder G. [mailto:removed_email_address@domain.invalid]
Sent: Friday, May 26, 2006 8:44 AM
> You can't call:
>
> irb(main):007:0> 'a'.!= 'b'
> SyntaxError: compile error
> (irb):7: parse error, unexpected tNEQ
> 'a'.!= 'b'
>       ^
>
> So it actually makes sense: you can't call, so you can't send.


Hmmm... Really :)
So, other question: is there way for uniform compare objects by some
operator? (where operator is either == or != or <, or even include?)

> -Alder

Victor.
Sam R. (Guest)
on 2006-05-26 10:13
(Received via mailing list)
Quoting removed_email_address@domain.invalid, on Fri, May 26, 2006 at 02:50:27PM 
+0900:
> So, other question: is there way for uniform compare objects by some
> operator? (where operator is either == or != or <, or even include?)

Perhaps <=>

Sam
Victor S. (Guest)
on 2006-05-26 10:16
(Received via mailing list)
From: Sam R. [mailto:removed_email_address@domain.invalid]
Sent: Friday, May 26, 2006 9:11 AM
> Quoting removed_email_address@domain.invalid, on Fri, May 26, 2006 at 02:50:27PM +0900:
> > So, other question: is there way for uniform compare objects by some
> > operator? (where operator is either == or != or <, or even include?)
>
> Perhaps <=>

No-no.

The point was to do things like this:

def filter(object, op, criteria)
  object.send op, criteria
end

filter 'a', :==, 'b'
filter 'Ruby', :include?, 'Ru'
filter 110, :<, 15

#filter 'a', :!=, 'b' <== doesn't work! :(

> Sam

V.
Sam R. (Guest)
on 2006-05-26 10:32
(Received via mailing list)
Quoting removed_email_address@domain.invalid, on Fri, May 26, 2006 at 03:16:20PM 
+0900:
> The point was to do things like this:
>
> def filter(object, op, criteria)
>   object.send op, criteria
> end
>
> filter 'a', :==, 'b'
> filter 'Ruby', :include?, 'Ru'
> filter 110, :<, 15
>
> #filter 'a', :!=, 'b' <== doesn't work! :(

Ok, I see.

Probably, its because you are showing us a small piece of a larger
puzzle, but
why not have filter take a block:

  def filter(object, op, criteria)
     yield object, criteria
  end
  filter('a', 'b') { |o,c| o != c }

or even a proc:

  def filter(object, op, criteria)
     op.call(object, criteria)
  end
  filter('a', Proc.new{ |o,c| o != c }, 'b')

Cheers,
Sam
Victor S. (Guest)
on 2006-05-26 10:50
(Received via mailing list)
From: Sam R. [mailto:removed_email_address@domain.invalid]
Sent: Friday, May 26, 2006 9:30 AM
> > No-no.
> >
>   end
>   filter('a', 'b') { |o,c| o != c }
>
> or even a proc:
>
>   def filter(object, op, criteria)
>      op.call(object, criteria)
>   end
>   filter('a', Proc.new{ |o,c| o != c }, 'b')

OK, some more pieces of puzzle :)

1. really, the former is used as bunch of filters:

Request.filter [
  [:base_type, :==, 'cpu'],
  [:fullname, :include?, 'Intel'],
  [:frequency, :>, 2300]
]

2. I'm planning inside Request to do the following:
a) search some pre-fetched array (through Array#select)
b) so some additional request to database

For (a), filter as lambda is good; but for (b), I need some format I can
convert into plain SQL.

Strange things, right? :)

> Sam

V.
Dave B. (Guest)
on 2006-05-26 11:11
(Received via mailing list)
Victor S. wrote:
> > > filter 110, :<, 15
>   [:frequency, :>, 2300]
> ]
>
> 2. I'm planning inside Request to do the following:
> a) search some pre-fetched array (through Array#select)
> b) so some additional request to database
>
> For (a), filter as lambda is good; but for (b), I need some format I can
> convert into plain SQL.

From ZenSpider's Ruby QuickRef, with a couple of corrections:
http://www.zenspider.com/Languages/Ruby/QuickRef.html#22

Operators by Precedence:
:: .
[]
**
-(unary) +(unary) ! ~
*  /  %
+  -
<<  >>
&
|  ^
>  >=  <  <=
<=> == === != =~ !~
&&
||
.. ...
=(+=, -=...)
not
and or

All of the above are just methods except these:

=, .., ..., !, not, &&, and, ||, or, !=, !~, ::

In addition, assignment operators(+= etc.) are not user-definable.

You may want to transform &&, || and != into a certain proc and a
certain other string for use in SQL.

Perhaps something like this:

op = Hash.new do |h, k|
  { :sql => k,
    :proc => proc {|obj, *args| obj.send(k, *args) } }
end

op["&&"] = {:sql => " AND ", :proc => proc {|l,r| l && r } }
op["||"] = {:sql => " OR ", :proc => proc {|l,r| l || r } }
op["!="] = {:sql => " <> ", :proc => proc {|l,r| l != r } }
op["=="] = {:sql => " = ", :proc => proc {|l,r| l == r } }

op[">"][:sql]  #=> ">"
op[">"][:proc].call(2, 1)  #=> true

Cheers,
Dave
Daniel S. (Guest)
on 2006-05-26 11:20
(Received via mailing list)
> said to me:
>
> tricks.rb:11:in `Kernel#send': undefined method `!=' for "a":String
> (NoMethodError)

The syntax magic makes != work... but that doesn't mean you can't create
methods to do the same things. define_method is much more lenient on
method names than def is:

class Object
  define_method(:<) {|arg| self < arg }
  define_method(:>) {|arg| self > arg }
  define_method(:!=) {|arg| self != arg }
end

1.send(:>, 5)
=> false

1.send(:<, 5)
=> true
Victor S. (Guest)
on 2006-05-26 11:24
(Received via mailing list)
From: Daniel S. [mailto:removed_email_address@domain.invalid]
Sent: Friday, May 26, 2006 10:18 AM
> > said to me:
>   define_method(:>) {|arg| self > arg }
>   define_method(:!=) {|arg| self != arg }
> end
>
> 1.send(:>, 5)
> => false
>
> 1.send(:<, 5)
> => true

Wow! Elegant. Thanks.

V.
Dave B. (Guest)
on 2006-05-26 11:27
(Received via mailing list)
On 5/26/06, Daniel S. wrote:
> 1.send(:>, 5)
> => false
>
> 1.send(:<, 5)
> => true

A good point.

:< and :>, though, are already methods!

1.methods.include? ">"  #=> true

Cheers,
Dave
Alder G. (Guest)
on 2006-05-26 11:45
(Received via mailing list)
On 5/26/06, Daniel S. <removed_email_address@domain.invalid> wrote:
>
Trying to define a method != doesn't wfm, even with define_method:

irb(main):013:0> class Object; define_method(:!=) {|arg| self != arg };
end
class Object; define_method(:!=) {|arg| self != arg }; end

SyntaxError: compile error
(irb):13: parse error, unexpected tNEQ, expecting tSTRING_CONTENT or
tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
class Object; define_method(:!=) {|arg| self != arg }; end
                               ^
Dave B. (Guest)
on 2006-05-26 11:51
(Received via mailing list)
On 5/26/06, Alder G. wrote:
> Trying to define a method != doesn't wfm, even with define_method:
>
> irb(main):013:0> class Object; define_method(:!=) {|arg| self != arg }; end
> class Object; define_method(:!=) {|arg| self != arg }; end
>
> SyntaxError: compile error
> (irb):13: parse error, unexpected tNEQ, expecting tSTRING_CONTENT or
> tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
> class Object; define_method(:!=) {|arg| self != arg }; end
>                                ^

No, just that symbol syntax. :!= is not a valid symbol. "!=" will work
just fine, though.

irb(main):001:0> class << self
irb(main):002:1> define_method("!=") {}
irb(main):003:1> end
=> #<Proc:0x00000000@(irb):3>

Cheers,
Dave
Robert K. (Guest)
on 2006-05-26 12:12
(Received via mailing list)
2006/5/26, Victor S. <removed_email_address@domain.invalid>:

> > > #filter 'a', :!=, 'b' <== doesn't work! :(
> >   filter('a', 'b') { |o,c| o != c }
> 1. really, the former is used as bunch of filters:
>
> For (a), filter as lambda is good; but for (b), I need some format I can
> convert into plain SQL.

This solution is not very nice, but the usage of != as symbol in
awkward anyway, the only way I got it to work is this:

irb(main):036:0> :'!='
=> :"!="

module Enumerable
  def filter(criteria)
    select do |x|
      criteria.all? do |member, op, value|
        if op == "!="
          x.send(member) != value
        else
          x.send(member).send(op, value)
        end
      end
    end
  end
end

irb(main):024:0> St = Struct.new :name, :size
=> St
irb(main):025:0> a=[St.new("foo", 10), St.new("bar", -20)]
=> [#<struct St name="foo", size=10>, #<struct St name="bar", size=-20>]
irb(main):026:0> a.filter [ [:name , "!=" , "foo"], [:size , :< , 0] ]
=> [#<struct St name="bar", size=-20>]
irb(main):027:0> a.filter [ [:name , "!=" , "foo"], [:size , :> , 0] ]
=> []

> Strange things, right? :)

No, IMHO that's a perfectly valid requirement.

Kind regards

robert
Alder G. (Guest)
on 2006-05-26 12:13
(Received via mailing list)
On 5/26/06, Dave B. <removed_email_address@domain.invalid> wrote:
> >                                ^
> Dave
Yup, good tip. However, the relations between the operator syntax and
the method calls reveals itself to be more mysterious than I thought:

class Foo
  define_method('!=') { 'Foo#!= was called' }
  define_method('==') { 'Foo#== was called' }
end

irb(main):003:0> foo = Foo.new
#<Foo:0x2c88e28>

irb(main):004:0> foo != 1
false   # looks like 'foo != arg' isn't simply syntactic sugar for
!foo.==(arg)

irb(main):005:0> foo.==
"Foo#== was called"

irb(main):008:0> foo.send '!='
"Foo#!= was called"      # And send seems to be the only way to call !=

But as far as Victor is concerned, as long as #send is used, those
methods would work as expected.
Justin C. (Guest)
on 2006-05-26 12:34
(Received via mailing list)
Alder G. wrote:
>> > tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
>>
>
> irb(main):003:0> foo = Foo.new
> #<Foo:0x2c88e28>
>
> irb(main):004:0> foo != 1
> false   # looks like 'foo != arg' isn't simply syntactic sugar for
> !foo.==(arg)
>

Actually, it still is:

foo.==(1) returns the string 'Foo#== was called' which is true. Then it
is negated: false.

Try changing it to:

class Foo
 define_method('!=') { puts 'Foo#!= was called' }
 define_method('==') { puts 'Foo#== was called' }
end

And you will see it call '=='.

-Justin
Alder G. (Guest)
on 2006-05-26 13:11
(Received via mailing list)
On 5/26/06, Justin C. <removed_email_address@domain.invalid> wrote:
> >> >
> >> irb(main):002:1> define_method("!=") {}
> >  define_method('!=') { 'Foo#!= was called' }
>
> end
>
> And you will see it call '=='.
>
> -Justin
>

Do'h!  You are correct, of course.
This topic is locked and can not be replied to.