Cool: nil is a class that can have methods

Excuse a newbee's enthusiasm, but this is really cool. It makes some code that would have had to treat nil specially.

class NilClass
  def each
    yield(self)
  end
  def length
    0
  end
end

a = nil
a.each {|a| puts a.class }

Doing it at the Object level is even more handy for the what I was playing with.

class Object
  def each
    yield(self)
  end
  def length
    if self == nil then 0 else 1 end
  end
end

a = nil
a.each {|a| puts a.length }

So every Object has an each method, which yields itself and has a length of 1, so everything can be treated like an array.
Really neat language.

Hi --

Excuse a newbee's enthusiasm, but this is really cool. It makes some code that would have had to treat nil specially.

class NilClass
  def each
    yield(self)
  end
  def length
    0
  end
end

a = nil
a.each {|a| puts a.class }

Doing it at the Object level is even more handy for the what I was playing with.

class Object
  def each
    yield(self)
  end
  def length
    if self == nil then 0 else 1 end
  end
end

a = nil
a.each {|a| puts a.length }

So every Object has an each method, which yields itself and has a length of 1, so everything can be treated like an array.
Really neat language.

Do be careful, though. Remember that the changes you make to Object
and NilClass will be in effect for all the library code that you
include in your application, including the standard library, so if
anyone else is relying on the fact that some objects respond to "each"
and others don't, or that nil is dimensionless, something could go
wrong.

David

···

On Sat, 20 May 2006, Rob Burrowes wrote:

--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
   > Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
   > Ruby for Rails

dblack@wobblini.net wrote:

Hi --

Excuse a newbee's enthusiasm, but this is really cool. It makes some code that would have had to treat nil specially.

class NilClass
    def each
        yield(self)
    end
    def length
        0
    end
end

a = nil
a.each {|a| puts a.class }

Doing it at the Object level is even more handy for the what I was playing with.

class Object
    def each
        yield(self)
    end
    def length
        if self == nil then 0 else 1 end
    end
end

a = nil
a.each {|a| puts a.length }

So every Object has an each method, which yields itself and has a length of 1, so everything can be treated like an array.
Really neat language.

Do be careful, though. Remember that the changes you make to Object
and NilClass will be in effect for all the library code that you
include in your application, including the standard library, so if
anyone else is relying on the fact that some objects respond to "each"
and others don't, or that nil is dimensionless, something could go
wrong.

David

This is what namespace selectors would help fix right? Was there ever a decision made about how that would work? Is it in 1.9 now?

-Jeff

···

On Sat, 20 May 2006, Rob Burrowes wrote:

Good point.

Looked sort of handy in the log filter I produced to generate gnuplot files. Nil data has meaning in the plot, as distinct from a 0. It is also handy to treat a single result in the same way as an array result. The collation of the data, from the logs to the plot data file, is being driven by an XML description, with embedded ruby expressions as XML attributes and text. These XML expressions get converted into methods to parse the logs. Having the targets of the expressions work seamlessly, despite them being nil, single values or arrays, was quite neat.

In the nil case, I wanted it to iterate and be printed as in the same way as a non-nil value. In the plot data, a nil prints as '-'. I hadn't thought of other code expecting to fail when the value was nil or not an array. They probably wont want nil to have a to_s() returning '-' either, not that anything has failed doing this, in this instance.

I am modifying it to output multiple rows, for generating Histograms, so I will look at doing this in a less dangerous way.

···

On 20/05/2006, at 12:20 PM, dblack@wobblini.net wrote:

Hi --

On Sat, 20 May 2006, Rob Burrowes wrote:

Excuse a newbee's enthusiasm, but this is really cool. It makes some code that would have had to treat nil specially.

class NilClass
  def each
    yield(self)
  end
  def length
    0
  end
end

a = nil
a.each {|a| puts a.class }

Doing it at the Object level is even more handy for the what I was playing with.

class Object
  def each
    yield(self)
  end
  def length
    if self == nil then 0 else 1 end
  end
end

a = nil
a.each {|a| puts a.length }

So every Object has an each method, which yields itself and has a length of 1, so everything can be treated like an array.
Really neat language.

Do be careful, though. Remember that the changes you make to Object
and NilClass will be in effect for all the library code that you
include in your application, including the standard library, so if
anyone else is relying on the fact that some objects respond to "each"
and others don't, or that nil is dimensionless, something could go
wrong.

David

--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
  > Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
  > Ruby for Rails

Quoting dblack@wobblini.net, on Sat, May 20, 2006 at 09:20:20AM +0900:

Do be careful, though. Remember that the changes you make to Object
and NilClass will be in effect for all the library code that you
include in your application, including the standard library, so if
anyone else is relying on the fact that some objects respond to "each"
and others don't, or that nil is dimensionless, something could go
wrong.

Whats the current wisdom on how to do this more nicely?

I've got a library that added #to_time to the Date builtin... and its
conflicting with another much more commonly used library, that has done
the same thing, but give time in local TZ, not UTC. Oops...

Easy way, is to move my code out into a utility method

module Util
  def to_time(v)
    case v
    when Time
      v
    when Date
      ... cvt v to a Time ..
    else
     ... ?
    end
  end
end

but switches on class type are usally a bad thing... in OO code
generally, and in ruby in particular we are supposed to duck-type, and
its a real posibility that also DateTime, and perhaps even other date or
time classes might wander into my code. I'd really like not have this
kind of switch statement.

What to do?

I could change my method name from Date#to_time, to
Date#vpim_to_time_utc, basically namespacing my extension, and adding
one to Time as well.

I was also considering having some kind of hash:

module Util
  @@cvt_to_time_utc = {
    Time => lambda{|t| t },
    Date => lambda(|d| Time.utc(d.year, d.mon, d.day)
    }
  def self.cvt_to_time_utc(v)
    @@cvt_to_time_utc[v.class].call(v)
  end
end

Then 3rd party classes could register some handlers to convert to Time
in UTC, and I wouldn't have to modify my case statements.

But... what if they have

  class MyTime < Time
  end

That won't work... so I could maybe be more clever, search their
ancestry looking for something that is in my hash.... This is starting
to be a bit of work, and unfotunately similar to what ruby does for
method dispatch...

Maybe just using name mangling, using my library prefix, is the way to
go!

Thoughts?

Cheers,
Sam

Quoting rob@cs.auckland.ac.nz, on Sat, May 20, 2006 at 09:50:49AM +0900:

In the nil case, I wanted it to iterate and be printed as in the same
way as a non-nil value. In the plot data, a nil prints as '-'. I
hadn't thought of other code expecting to fail when the value was nil
or not an array. They probably wont want nil to have a to_s()
returning '-' either, not that anything has failed doing this, in
this instance.

The temptation to change the core classes to work a little more like you
want is almost overwhelming... at least I have found it so. I guess in
this case you could do:

def gnuplot_each(v, &proc)
  if v.respond_to? :each
    v.each &proc
  else
    yield v
  end
end

then instead of doing

  data.each {..}

you could do

  gnuplot_each(data) {...}

cheers,
Sam

It's not in 1.9 yet. AFAIK this is the last thing we heard about selector
namespaces coming from matz (albeit indirectly):

  "He has fixed the SelectorNamespace specification, however, which is only in
  his mind now."

See http://redhanded.hobix.com/cult/rubyspameeting2006.html

As for the specification, [ruby-dev:27417] might give some clues.

···

On Sat, May 20, 2006 at 09:42:11AM +0900, Jeff Rose wrote:

This is what namespace selectors would help fix right? Was there ever a
decision made about how that would work? Is it in 1.9 now?

--
Mauricio Fernandez - http://eigenclass.org - singular Ruby

Probably total sacrilege, but I was using this to have "nil" as a valid value in arithmetic and to treat numbers as if they were arrays (in a limited sense). The latter is easy to fix, by storing all numbers as 1 element arrays. This solves the iterator on "nil" too. All nil values will be in an array, so I just need to iterate on the array.

Using "nil" in arithmetic is to differentiate the no data state (nil), from having seen a data point, even a 0 value. Probably best to subclass Fixnum and build my own objects for arithmetic. Altering the numeric classes is definitely a tempting thing though.

I have XML definitions of the source log file and the resulting summary I want to get.
e.g.
a
<src>
  ...
         <column id="sourceadjacentaddress">
                 <type>string</type>
         </column>
         <column id="destadjacentaddress">
                 <type>string</type>
         </column>
  ...
</src>
<rslt>
  ...
         <column id="link1">
           <test exp="@src_sourceadjacentaddress == '00-D0-41-68-CF-56' || @src_destadjacentaddress == '00-D0-41-68-CF-56'"> </test>
           <value exp= "+= @src_d_tooctets+src_d_fromoctets"> </value>
           <type>int</type>
           <scale exp="/@groupby_duration.megabyte"> </scale>
           <format>%d</format>
         </column>
  ...
</rslt>

This gets turned into ruby code that parses the log. It uses modified column name as variables. The test expression determines if the output column is modified, and the value expression is used to set or alter the value. If the values start as nil, then adding a value, will initialise them. Meeting further values, will result in them being added on.

If multiple results are required (e.g. for a histogram), then a value expression like
  <value exp= "+= [@src_d_tooctets, @src_d_fromoctets]"> </value>
results in the to and from traffic being added to an array result called @rslt_link1, rather than a simple numeric result.

I did this by I adding "each" and "each_with_index" to every Object, thus allowing numbers and nil values to have an iterator.
I replaced the Fixnum + with one that would add arrays to numbers, giving an array result or Fixnum result, depending on the value being added.
Also the Arrays class was modified to add two arrays, by adding the elements at the same array index to each other, not concatenating the arrays.
I then committed the ultimate sin, and added a plus method to nil.

After all these hacks, I can
  add a number to an array, and the first element will get altered.
  add an array to a number, and get an Array with the first element altered
  add a number or Array to nil, and get that number or the Array

i.e.

class Object
  def each
    if self != nil then yield(self) end
  end
  def each_with_index
    if self != nil then yield(self,0) end
  end
  def length
    if self == nil then 0 else 1 end
  end
end

class Array
  def +(value)
    value.each_with_index { |x,i| self[i] += x }
    self
  end
end

class Fixnum
  alias oldPlus +
  def +(value)
    if(value.length == 1)
      self.oldPlus(value)
    else
      value.+(self)
    end
  end
end

class NilClass
  def +(value)
    value
  end
end

a = [1,3]
a += [5,2]
a.each {|b| puts b }
puts

a = 1
a += 2
a.each {|b| puts b }
puts

a += [5,2]
a.each {|b| puts b }
puts

a = nil
a += 10
a.each {|b| puts b }
puts

a = nil
a += [3,8]
a.each {|b| puts b }
puts

a = ["hello","I"]
a += [" world"," repent"]
a.each {|b| print b, " " }
puts

···

On 20/05/2006, at 2:18 PM, Sam Roberts wrote:

Quoting rob@cs.auckland.ac.nz, on Sat, May 20, 2006 at 09:50:49AM +0900:

In the nil case, I wanted it to iterate and be printed as in the same
way as a non-nil value. In the plot data, a nil prints as '-'. I
hadn't thought of other code expecting to fail when the value was nil
or not an array. They probably wont want nil to have a to_s()
returning '-' either, not that anything has failed doing this, in
this instance.

The temptation to change the core classes to work a little more like you
want is almost overwhelming... at least I have found it so. I guess in
this case you could do:

def gnuplot_each(v, &proc)
  if v.respond_to? :each
    v.each &proc
  else
    yield v
  end
end

then instead of doing

  data.each {..}

you could do

  gnuplot_each(data) {...}

cheers,
Sam