Destructive! operations

I've occasionally found this to be useful, in constructs such as:

unless url.sub!( %r(^file://), '' )
  raise "Invalid file URL: #{url}"
end

Here, the combination of performing the substitution and checking
whether it actually happened is quite useful.

Ian

···

On Tue 22 Feb 2005 at 09:10:44 +0900, Hal Fulton wrote:

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.

--
Ian Macdonald | Documentation is like sex: when it is good,
System Administrator | it is very, very good; and when it is bad,
ian@caliban.org | it is better than nothing. -- Dick
http://www.caliban.org | Brandon
                            >

Christian Neukirchen schrieb:

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

Pit Capitain <pit@capitain.de> writes:

Christian Neukirchen schrieb:

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.

No problem, the idea and implementation is correct.

···

Regards,
Pit

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

Pit Capitain <pit@capitain.de> writes:

Christian Neukirchen schrieb:

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.

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

  some_object.not_nil?.do_something

Regards,
Pit

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

E

···

On Mon, February 21, 2005 6:07 pm, Christian Neukirchen said:

ES schrieb:

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);
  }
>>> if (RTEST(rb_eval(self, node->nd_cond))) {
      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

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

Wouldn't be surprised... :slight_smile:

Cheers,
Navin.

···

Pit Capitain <pit@capitain.de> wrote:

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

ES schrieb:

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);
  }
>>> if (RTEST(rb_eval(self, node->nd_cond))) {
      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 :slight_smile:

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

Regards,
Pit

E

···

On Mon, February 21, 2005 8:04 pm, Pit Capitain said:

Pit Capitain <pit@capitain.de> writes:

ES schrieb:

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?

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

If he could, we wouldn't beg for #to_bool whenever possible...

···

Regards,
Pit

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

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

ES schrieb:

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:

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

:frowning:

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

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

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

···

--
Mark Sparshatt

Caio Tiago Oliveira schrieb:

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

ES schrieb:

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:

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

in the current ruby implementation this
is the case. hopefully an alternative
implementation will be available eventually :slight_smile:

(be it rubydium or ruby2c/metaruby)

Alex

···

On Feb 21, 2005, at 10:58 PM, Caio Tiago Oliveira wrote:

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

:frowning:

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

Navindra Umanee schrieb:

···

Pit Capitain <pit@capitain.de> wrote:

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

Hi Navin, just look at the "evil" project on rubyforge and you know what I mean.

Regards,
Pit

It's been a damn long time too...

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/4991
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/5056
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/5087

···

On Tue, 22 Feb 2005, Christian Neukirchen wrote:

Pit Capitain <pit@capitain.de> writes:
> 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...)
If he could, we wouldn't beg for #to_bool whenever possible...

_____________________________________________________________________
Mathieu Bouchard -=- Montréal QC Canada -=- http://artengine.ca/matju

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

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

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

···

On Mon, February 21, 2005 8:58 pm, mark sparshatt said:

Hi --

···

On Wed, 23 Feb 2005, Alexander Kellett wrote:

On Feb 21, 2005, at 10:58 PM, Caio Tiago Oliveira wrote:

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

:frowning:

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

in the current ruby implementation this
is the case. hopefully an alternative
implementation will be available eventually :slight_smile:

(be it rubydium or ruby2c/metaruby)

Although this raises the old question of what an "implementation of"
"Ruby" is....

David

--
David A. Black
dblack@wobblini.net

"David A. Black" <dblack@wobblini.net> writes:

Hi --

It shouldn't be in C. Such things should be in Ruby.
:frowning:
I don't know C, so I can't learn Ruby?
So can't I know the behaviours of my changes?

in the current ruby implementation this
is the case. hopefully an alternative
implementation will be available eventually :slight_smile:

(be it rubydium or ruby2c/metaruby)

Although this raises the old question of what an "implementation of"
"Ruby" is....

And that these are not necessarily easier to understand than the C
implementations...

···

On Wed, 23 Feb 2005, Alexander Kellett wrote:

On Feb 21, 2005, at 10:58 PM, Caio Tiago Oliveira wrote:

David

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

depends on what part of the re-implementation you mean.
the whole, or the part that implements the languages features,
the core of both ruby2c and rubydium are likely to pretty dang
complex, simply because they do difficult things :slight_smile:

otoh, the outer parts of the project, the things that users will
most likely want to look at to understand the ruby language from
the implementation, are likely to be much more readable than
there c counterparts.

of course. its damn good c code. it'll be a while till i personally
reach anything as readable as that. thats one limitation of having
only one coder :slight_smile:

Alex

···

On Feb 22, 2005, at 6:10 PM, Christian Neukirchen wrote:

And that these are not necessarily easier to understand than the C
implementations...