readable and provocative & daring

R

Richard Drake

A funny thing happened to me in irb this week. Well, to be honest it's
a reconstruction. And it was little more than one thing. But hopefully
you'll get the gist.

irb(main):001:0> readable = false
=> false
irb(main):002:0> readable and provocative & daring
=> false
irb(main):003:0> readable = nil
=> nil
irb(main):004:0> readable and provocative & daring
=> nil
irb(main):005:0> readable = "yes"
=> "yes"
irb(main):006:0> readable and provocative & daring
NameError: undefined local variable or method `provocative' for
main:Object
from (irb):6
irb(main):007:0> provocative = false
=> false
irb(main):008:0> readable and provocative & daring
NameError: undefined local variable or method `daring' for main:Object
from (irb):8

Fine so far. & is eager, it always seeks to evaluate its right hand
side. Fair cop. Let's move on.

irb(main):009:0> daring = nil
=> nil
irb(main):010:0> readable and provocative & daring
=> false
irb(main):011:0> provocative = nil
=> nil
irb(main):012:0> readable and provocative & daring
=> false

Hmm, a slightly surprising difference with and there. But does it
matter? It didn't to me at the time. I was Ruby newbie with an
important business problem to solve ...

irb(main):013:0> provocative = "yes "
=> "yes "
irb(main):014:0> readable and provocative & daring
NoMethodError: undefined method `&' for "yes ":String
from (irb):14

Aha. So I defined a little method in String and then ...

irb(main):020:0> readable and provocative & daring
=> nil
irb(main):021:0> daring = "please"
=> "please"
irb(main):022:0> readable and provocative & daring
=> "yes please"

Yep, that's it. Now let's really take this thing out for a spin:

irb(main):023:0> daring = [1000, " times ", "yes"]
=> [1000, " times ", "yes"]
irb(main):024:0> readable and provocative & daring
=> "yes 1000 times yes"
irb(main):025:0> provocative = ["please", "say", "yes"]
=> ["please", "say", "yes"]
irb(main):026:0> readable and provocative & daring
=> ["yes"]

Hmm.

The elided code was of course

class String
def & a
self + a.to_s if a
end
end

This was I stress again to solve a real world problem. Or, to be more
precise, to make an existing solution to a real world problem more
readable.

But it did feel a bit provocative and daring.

Any comments?

Richard
 
J

Justin Collins

Some interesting stuff there...but I think the main thing is that 'and'
is a Ruby keyword, whereas '&' is an instance method. '&' can be defined
as makes sense for whatever object it is being called on. Therefore,
something like
readable and provocative & daring

is equivalent to
readable and provocative.&(daring)

which means if readable is false, then provocative.& doesn't need to be
called at all. However, if readable is true, then it does something like
provocative.send:)&, daring)

If provocative doesn't exist, it can't call any methods on it. If
provocative does exist, but daring doesn't, then daring cannot be
evaluated and can't be passed in as a parameter to the function call.

However, once provocative and daring are defined, it can try to call the
provocative.& method, if it exists. And since you define it, all is good!

My apologies if you already realized all that! The way you have the
syntax and the fact that "and" and "&" are equivalent in English could
be confusing...

-Justin

Richard said:
A funny thing happened to me in irb this week. Well, to be honest it's
a reconstruction. And it was little more than one thing. But hopefully
you'll get the gist.

irb(main):001:0> readable = false
=> false
irb(main):002:0> readable and provocative & daring
=> false
irb(main):003:0> readable = nil
=> nil
irb(main):004:0> readable and provocative & daring
=> nil
irb(main):005:0> readable = "yes"
=> "yes"
irb(main):006:0> readable and provocative & daring
NameError: undefined local variable or method `provocative' for
main:Object
from (irb):6
irb(main):007:0> provocative = false
=> false
irb(main):008:0> readable and provocative & daring
NameError: undefined local variable or method `daring' for main:Object
from (irb):8

Fine so far. & is eager, it always seeks to evaluate its right hand
side. Fair cop. Let's move on.

irb(main):009:0> daring = nil
=> nil
irb(main):010:0> readable and provocative & daring
=> false
irb(main):011:0> provocative = nil
=> nil
irb(main):012:0> readable and provocative & daring
=> false

Hmm, a slightly surprising difference with and there. But does it
matter? It didn't to me at the time. I was Ruby newbie with an
important business problem to solve ...

irb(main):013:0> provocative = "yes "
=> "yes "
irb(main):014:0> readable and provocative & daring
NoMethodError: undefined method `&' for "yes ":String
from (irb):14

Aha. So I defined a little method in String and then ...

irb(main):020:0> readable and provocative & daring
=> nil
irb(main):021:0> daring = "please"
=> "please"
irb(main):022:0> readable and provocative & daring
=> "yes please"

Yep, that's it. Now let's really take this thing out for a spin:

irb(main):023:0> daring = [1000, " times ", "yes"]
=> [1000, " times ", "yes"]
irb(main):024:0> readable and provocative & daring
=> "yes 1000 times yes"
irb(main):025:0> provocative = ["please", "say", "yes"]
=> ["please", "say", "yes"]
irb(main):026:0> readable and provocative & daring
=> ["yes"]

Hmm.

The elided code was of course

class String
def & a
self + a.to_s if a
end
end

This was I stress again to solve a real world problem. Or, to be more
precise, to make an existing solution to a real world problem more
readable.

But it did feel a bit provocative and daring.

Any comments?

Richard
 
R

Richard Drake

My apologies if you already realized all that!

I did kinda realise all that, except I wasn't focusing on the fact that
'and' is a keyword. Is it only with keywords that the rhs of the
operator may not be evaluated? I don't think so - && and || have this
property. But I guess they cannot ever be redefined, right?

I had small questions and BIG questions here.

My BIG questions have to do with what seemed at the time a daring
extension of the meaning of '&'. Is such an extension sensible: -

1. just for my project, with four other Rubyists of differing vintages?
(I won't tell you what they've said so far, that could spoil the fun!)

2. if we were to release some of our work as open source to the whole
wide wonderful world of Ruby programmers?

I was starting with a reasonably complex conditional method that used
'+' on strings that may be nil. I soon came to realise that

a + b

works fine when they're both bona fide strings but gives an error when
either is nil. On the other hand

nil & b

is already defined as false, which seems operationally equivalent to
nil in every way so is exactly what I want. (Another of my small
questions, in passing. Are nil and false ever different in their
behavior?)

Extending '&' as I have - and the opening up of a core class and method
definition is so short and simple, I do love Ruby for that - we now
also have

"hello " & "cheeky" -> "hello cheeky"
"hello " & nil -> nil

What's great about this is the amount of brackets and branching it
removes from the original method.

What's weird about it is this.

12 & 7 -> 4

[3, 6, 9] & [2, 4, 6] -> [6]

In other words, '&' always reduces, the result is always <= in some
reasonable sense both arguments.

Until now.

But I still think that, in the highly pragmatic spirit of Ruby,
everyone should have such a useful meaning for '&' on Strings. I surely
does not harm and fits in brilliantly with the much used

blob || "not known"

and

blob ||= "starter for ten"

idioms.

But I'm a newb!

Thanks very much for the feedback.

Richard
 
M

Matthew Moss

&& and 'and' both exhibit the same behaviour, in that they short-circuit.

& is a combiner-and, not logical (rather, typically bitwise), which
requires it evaluate both sides of the expression.

Maybe you really wanted: readable and provocative && daring

Yes, of course, you can make your own versions, but you need to keep
this behaviour in mind.


def foo
p "foo"
false
end

foo && foo

foo || foo
"foo"
"foo"

foo & foo
"foo"
"foo"

foo and foo
 
M

Matthew Moss

Yes, of course, you can make your own versions, but you need to keep
this behaviour in mind.

Sorry, should have realized that you can make your own version of &
but not of &&.
 
R

Richard Drake

Sorry, should have realized that you can make your own version
of & but not of &&.

Yes, and it was the ability to extend & to String that started as a
'what if?' this time last week and ended with some serious questions
about how wide the utility of this version may be. Or perhaps Ruby
veterans would vote it down for reasons I might not currently grasp?

Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top