destructive! operations

G

gabriele renzi

Robert Klemme ha scritto:
I didn't miss this "feature" either. I suspect that an unfinished
transition from Perl to Ruby makes people voice such whishes... :)

or an unfinished transition to smalltalk/python :)
I don't like the idea of letting objects decide if they are true or not,
but it may have some use cases (i.e. for proper proxy objects)
 
B

Brian Schröder

gets returns nil on EOF.

Yes, and you wanted a nil that eats its messages silently. So it would
also eat chomp. I meant, if you have a all eating nil then
nil.ignore_if_nil.chomp === nil.chomp.

Regards,

Brian
 
N

Navindra Umanee

Robert Klemme said:
I didn't miss this "feature" either. I suspect that an unfinished
transition from Perl to Ruby makes people voice such whishes... :)

Or maybe Lisp where '() and nil are the same...

-N.
 
N

Navindra Umanee

Austin Ziegler said:
That's not inconsistent; you're just not understanding. Matz posted
about this some time back and its a perfectly clear and consistent
way of working. Let's say you have an empty Array, 'a':

Thanks for the explanation!
It's regular. It's explained. It makes sense. It just doesn't work
like a P language. I doubt you'll find many experienced Ruby
programmers -- or novice Ruby programmers who don't expect Ruby to
act like a P language -- who are confused about this issue.

I don't really understand why you bring up P languages. It's complex
and unexpected behaviour that you have explained the cause of, but I
fail to see why this particular Ruby Way is more useful or desireable.

Seems mostly like an implementation detail to me but it's good to know
there is an explanation. I probably missed the point. :)

Cheers,
Navin.
 
P

Pit Capitain

Here you go:

EATING_NIL = Object.new

def EATING_NIL.nil?
true
end

def EATING_NIL.method_missing(*)
self
end

class Object
def ignore_if_nil
self
end
end

def nil.ignore_if_nil
EATING_NIL
end

Regards,
Pit
 
P

Pit Capitain

Christian said:
Unfortunately, that would make the loop turn endless, as:

irb(main):021:0> puts "Doesn't work as I want" if EATING_NIL
Doesn't work as I want

DOH! Here's the test I wrote for the code:

if EATING_NIL then puts("nil") else puts("not nil") end
It can't be done in Ruby-only, I think.

After briefly looking at the source code, I think so too. Sorry for the noise.

Regards,
Pit
 
R

Robert Klemme

Navindra Umanee said:
Thanks for the explanation!


I don't really understand why you bring up P languages. It's complex
and unexpected behaviour that you have explained the cause of, but I
fail to see why this particular Ruby Way is more useful or desireable.

I find it desirable because usually you calculate range values from the
array at hand. If you make a mistake then this will show up soon with this
behavior. Consider:

def treat_subarray(ar, el, &b)
low = ar.index el
high = ar.rindex el
# oops, accidentally exchanged indexes
ar[high .. low].each &b if high && low
end

Now, what happens is this:
a = %w{a b c d e a j e a o p} => ["a", "b", "c", "d", "e", "a", "j", "e", "a", "o", "p"]
treat_subarray( a, "a" ) {|e| p e}
NoMethodError: undefined method `each' for nil:NilClass
...

You probably would not detect this error so soon if you just got an empty
array back - you might just think that there are no matching elements in the
array.
Seems mostly like an implementation detail to me but it's good to know
there is an explanation. I probably missed the point. :)

Probably. :)

Kind regards

robert
 
R

Robert Klemme

Pit Capitain said:
Here you go:

EATING_NIL = Object.new

def EATING_NIL.nil?
true
end

def EATING_NIL.method_missing(*)
self
end

class Object
def ignore_if_nil
self
end
end

def nil.ignore_if_nil
EATING_NIL
end

No, that's not the solution wanted because
booom!
=> nil

EATING_NIL does not behave like false which was a requirement. Currently
the only solution I see is to do "def nil.method_missing(*a,&b) self end" -
but that is not desirable because it will make a lot errors hard to detect.

Kind regards

robert
 
E

ES

Apologies beforehand, I can't access the NG, just the ML,
so I don't know if these have already been covered.

Wouldn't it be possible to override the TrueClass, NilClass
and FalseClass methods to yield the correct behaviour for
this object? I'm assuming 'if something' expands to
'if something == true' or something like that?
No problem, the idea and implementation is correct.

I think I'd be partial to calling the method #not_nil? instead;
mainly because it's shorter :)

some_object.not_nil?.do_something

E
 
P

Pit Capitain

ES said:
Wouldn't it be possible to override the TrueClass, NilClass
and FalseClass methods to yield the correct behaviour for
this object? I'm assuming 'if something' expands to
'if something == true' or something like that?

If you look at the Ruby source code (this is 1.8.2), in eval.c:

case NODE_IF:
if (trace_func) {
call_trace_func("line", node, self,
ruby_frame->last_func,
ruby_frame->last_class);
}node = node->nd_body;
}
else {
node = node->nd_else;
}
goto again;

This is the code to handle an if statement. The marked line is the code that
evaluates the condition. The "then"-part of the if statement is executed iff the
RTEST macro returns true (in C). RTEST is defined in ruby.h as:

/* special contants - i.e. non-zero and non-fixnum constants */
#define Qfalse 0
#define Qtrue 2
#define Qnil 4

#define RTEST(v) (((VALUE)(v) & ~Qnil) != 0)

The objects false, true, and nil are encoded internally as 0, 2, and 4
respectively. (You can get those values in Ruby with "p false.id".) The only
values for which RTEST returns false (in C) are the values 0 and 4, in other
words the objects false and nil. So more or less

if something

expands to

if something != nil && something != false

I think Christian is right that you cannot work around this in Ruby. (Maybe
Florian Groß can do it...)

Regards,
Pit
 
N

Navindra Umanee

Pit Capitain said:
I think Christian is right that you cannot work around this in Ruby. (Maybe
Florian Groß can do it...)

Hehehe. Why? Is Florian known for pushing the frontier as to what it
is possible in Ruby?

Wouldn't be surprised... :)

Cheers,
Navin.
 
E

ES

If you look at the Ruby source code (this is 1.8.2), in eval.c:

case NODE_IF:
if (trace_func) {
call_trace_func("line", node, self,
ruby_frame->last_func,
ruby_frame->last_class);
}
node = node->nd_body;
}
else {
node = node->nd_else;
}
goto again;

This is the code to handle an if statement. The marked line is the code that
evaluates the condition. The "then"-part of the if statement is executed iff
the
RTEST macro returns true (in C). RTEST is defined in ruby.h as:

/* special contants - i.e. non-zero and non-fixnum constants */
#define Qfalse 0
#define Qtrue 2
#define Qnil 4

#define RTEST(v) (((VALUE)(v) & ~Qnil) != 0)

The objects false, true, and nil are encoded internally as 0, 2, and 4
respectively. (You can get those values in Ruby with "p false.id".) The only
values for which RTEST returns false (in C) are the values 0 and 4, in other
words the objects false and nil. So more or less

if something

expands to

if something != nil && something != false

Well, this *would* be overridable. If, however, the test is done at the C
level through direct object ID comparison, things are a bit more complicated.
The only option, then, would be to masquerade as Qnil while adding the
necessary behaviour.

I suppose the question is, then, is it necessary to have the above behaviour?
As I understood it, the desired functionality was something like (my syntax):

ob.not_nil?.do_something

Conceptually expands to:

ob.do_something unless ob.nil?

For this purpose, it should be sufficient to add a method to both Object
and NilClass. NilClass could then return an object that simply consumes
all methods fed to it and propagates itself after each call, like was
described in the original post as far as I can recall its contents. This
behaviour would then not be accessible except when using NilClass#not_nil?
so it wouldn't cause problems in other conditionals. Is there a use case
where this would cause a problem, or why is it desirable that the explicit
comparison be allowed for the special NIL and not just the chaining?

Again, sorry if this has already been covered; feel free not to reply,
I'll read the NG in the evening. I'm just bored at work :)
I think Christian is right that you cannot work around this in Ruby. (Maybe
Florian Groß can do it...)

Regards,
Pit

E
 
M

mark sparshatt

ES wrote:

I suppose the question is, then, is it necessary to have the above behaviour?
As I understood it, the desired functionality was something like (my syntax):

ob.not_nil?.do_something

Conceptually expands to:

ob.do_something unless ob.nil?

For this purpose, it should be sufficient to add a method to both Object
and NilClass. NilClass could then return an object that simply consumes
all methods fed to it and propagates itself after each call, like was
described in the original post as far as I can recall its contents. This
behaviour would then not be accessible except when using NilClass#not_nil?
so it wouldn't cause problems in other conditionals. Is there a use case
where this would cause a problem, or why is it desirable that the explicit
comparison be allowed for the special NIL and not just the chaining?

Again, sorry if this has already been covered; feel free not to reply,
I'll read the NG in the evening. I'm just bored at work :)

The problem with this solution is the new object won't behave like nil
in an if expression

if ob.not_nil?.do_something
code
end

would run the code when obj is nil

There seems to be 2 requirements
the nil object shouldn't be changed, in order to not hide any errors
the new nil object should behave like nil when tested

that's why it can't be done in pure ruby
 
C

Caio Tiago Oliveira

Pit Capitain, 21/2/2005 17:04:
If you look at the Ruby source code (this is 1.8.2), in eval.c:

It shouldn't be in C. Such things should be in Ruby.

:(

I don't know C, so I can't learn Ruby?
So can't I know the behaviours of my changes?
 
E

ES

ES wrote:



The problem with this solution is the new object won't behave like nil
in an if expression

if ob.not_nil?.do_something
code
end

would run the code when obj is nil

Ah. Overextending the idiom :) I'd say it works fine as a shortcut.
In the above scenario, if 'code' is a simple operation, one should
just do:

ob.not_nil?.do_something.code

Otherwise (or if 'code' is unrelated to the object), since we're
using a conditional *anyway*, one should do:

unless ob.nil?
ob.do_something()
code
end

So it's conceptually OK. The only issue is that it won't throw an error
if used incorrectly which may cause problems.

Now, a possible solution would be to cause NilClass#not_nil? to redefine
NilClass#method_missing and any other operation to clear the redefinition.
This would, unfortunately, prevent chaining except as follows:

ob.not_nil?.do_something.not_nil?.do_anotherthing

It's probably not thread-safe, though :)
There seems to be 2 requirements
the nil object shouldn't be changed, in order to not hide any errors
the new nil object should behave like nil when tested

that's why it can't be done in pure ruby

Mark Sparshatt

E
 
H

Hal Fulton

Navindra said:
I don't really understand why you bring up P languages. It's complex
and unexpected behaviour that you have explained the cause of, but I
fail to see why this particular Ruby Way is more useful or desireable.

Seems mostly like an implementation detail to me but it's good to know
there is an explanation. I probably missed the point. :)

I have always had the feeling that there were interesting use cases
for this, but I have never known an example. :) It's a bit of behavior
that I've just learned to accept via Matz's explanation. In short,
I'm used to it.

This is in contrast to the fact that certain bang methods sometimes
return nil -- that behavior I've also seen justified, and can easily
imagine use cases, but I still have never liked it. It's one of my
most common bugs, personally. And not once have I ever *wanted* the
"return nil" behavior.


Hal
 
N

Navindra Umanee

Hal Fulton said:
I have always had the feeling that there were interesting use cases
for this, but I have never known an example. :) It's a bit of behavior
that I've just learned to accept via Matz's explanation. In short,
I'm used to it.

This is in contrast to the fact that certain bang methods sometimes
return nil -- that behavior I've also seen justified, and can easily
imagine use cases, but I still have never liked it. It's one of my
most common bugs, personally. And not once have I ever *wanted* the
"return nil" behavior.

Ahh, good to know I'm not alone in the world!

Btw, in case anyone gets the wrong idea, all this complaining just
means I just love Ruby more. :)

Cheers,
Navin.
 
G

Gavin Kistner

Robert Klemme ha scritto:


or an unfinished transition to smalltalk/python :)

or an unfinished transition from Javascript

There are a lot of languages where "", 0 and others are treated as
non-truth values.
I love that Ruby isn't one of them.

...

But I do support the idea of a single, consistent method across many
classes which points out vapid values.

Hey, how about that for a name?
"".vapid? #=> true

:)
 
P

Pit Capitain

Caio said:
Pit Capitain, 21/2/2005 17:04:


It shouldn't be in C. Such things should be in Ruby.

Where do you draw the line between core functionality implemented in something
like C and add-ons implemented in Ruby?
I don't know C, so I can't learn Ruby?
So can't I know the behaviours of my changes?

Of course you can. The behavior of "if" is documented here, for example:

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html#UH

I quoted the corresponding source code only to show that there seems to be no
way to implement an "eating nil" in pure Ruby.

Regards,
Pit
 
G

Gavin Kistner

This is in contrast to the fact that certain bang methods sometimes
return nil -- that behavior I've also seen justified, and can easily
imagine use cases, but I still have never liked it. It's one of my
most common bugs, personally. And not once have I ever *wanted* the
"return nil" behavior.

ditto - foo.gsub!(...).gsub!(...).gsub!(...).damn.
 

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

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top