Method '!='

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.

Victor Shepelev wrote:

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.

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

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

-Justin

I've tried something like this:

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

Sorry. Return 'false', of couse.

V.

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)

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 Shepelev wrote:
> 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.
>
>
>

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.

···

From: Justin Collins [mailto:collinsj@seattleu.edu]
Sent: Friday, May 26, 2006 8:28 AM

> 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)

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

Wow! Elegant. Thanks.

V.

···

From: Daniel Sheppard [mailto:daniels@pronto.com.au]
Sent: Friday, May 26, 2006 10:18 AM

A good point.

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

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

Cheers,
Dave

···

On 5/26/06, Daniel Sheppard wrote:

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

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
                               ^

···

On 5/26/06, Daniel Sheppard <daniels@pronto.com.au> wrote:

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

--
-Alder

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.

···

On 5/26/06, Victor Shepelev <vshepelev@imho.com.ua> wrote:

From: Justin Collins [mailto:collinsj@seattleu.edu]
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

--
-Alder

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

···

On 5/26/06, Alder Green 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
                               ^

> From: Justin Collins [mailto:collinsj@seattleu.edu]
> 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.

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

-Alder

Victor.

···

From: Alder Green [mailto:alder.green@gmail.com]
Sent: Friday, May 26, 2006 8:44 AM

On 5/26/06, Victor Shepelev <vshepelev@imho.com.ua> wrote:

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.

···

On 5/26/06, Dave Burt <dave@burt.id.au> wrote:

On 5/26/06, Alder Green 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

--
-Alder

Quoting vshepelev@imho.com.ua, 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

Alder Green 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

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)

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

···

On 5/26/06, Dave Burt <dave@burt.id.au> wrote:

On 5/26/06, Alder Green wrote:

Quoting vshepelev@imho.com.ua, 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! :frowning:

Sam

V.

···

From: Sam Roberts [mailto:sroberts@uniserve.com]
Sent: Friday, May 26, 2006 9:11 AM

Do'h! You are correct, of course.

···

On 5/26/06, Justin Collins <collinsj@seattleu.edu> wrote:

Alder Green wrote:
> On 5/26/06, Dave Burt <dave@burt.id.au> wrote:
>> On 5/26/06, Alder Green 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
>
> 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)
>

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

Quoting vshepelev@imho.com.ua, on Fri, May 26, 2006 at 03:16:20PM +0900:

From: Sam Roberts [mailto:sroberts@uniserve.com]
Sent: Friday, May 26, 2006 9:11 AM
> Quoting vshepelev@imho.com.ua, 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! :frowning:

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

Quoting vshepelev@imho.com.ua, on Fri, May 26, 2006 at 03:16:20PM +0900:
> From: Sam Roberts [mailto:sroberts@uniserve.com]
> Sent: Friday, May 26, 2006 9:11 AM
> > Quoting vshepelev@imho.com.ua, 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! :frowning:

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')

OK, some more pieces of puzzle :slight_smile:

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? :slight_smile:

Sam

V.

···

From: Sam Roberts [mailto:sroberts@uniserve.com]
Sent: Friday, May 26, 2006 9:30 AM

Victor Shepelev wrote:

> > > > So, other question: is there way for uniform compare objects by some
> > > > operator? (where operator is either == or != or <, or even include?)
> > 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! :frowning:

OK, some more pieces of puzzle :slight_smile:

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.

From ZenSpider's Ruby QuickRef, with a couple of corrections:

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

> > 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! :frowning:
>
> 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')

OK, some more pieces of puzzle :slight_smile:

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.

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? :slight_smile:

No, IMHO that's a perfectly valid requirement.

Kind regards

robert

···

2006/5/26, Victor Shepelev <vshepelev@imho.com.ua>:

--
Have a look: Robert K. | Flickr