--------------CC4D4D01074E3372F83EC9CB
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Have you had any further thoughs on this matz?

as far as a "nice solution proposal", the only thing that I can suggest is that the
special global object "null" is defined.
null would be an instance of class Null.

this allows a developer to use the global "null" or a user instanciated named "null"
which may be is useful for debugging.

1. Instances of class Null, are handled specially by:  if (condition) then ... else ...
end and do not execute either the then or the else clauses.
2. Instances of class Null either simply implemetn method_missing to return null, or have
some way to skip the call cahin as indicated in Q3 below.

I have appended some source code at  the end of this email, which is far from final but
works sufficiently to test the concepts out.

cheers

Keith
--------------------------------
Yukihiro Matsumoto wrote:

> Hi,
>
> In message "[ruby-talk:17721] Null Pattern"
>     on 01/07/12, Keith Hodges <K.Hodges / ftel.co.uk> writes:
>
> |Q.1 What is the best way to define a new global constant like "nil" (i.e. lowercase).
>
> There's only one way: hack the parser.  Pseudo variables: nil, false,
> true, self, __FILE__, and __LINE__ are built in Ruby syntax.
>
> |Q.2 I would like to be able to obtain information about the instanciator of aNull
> |so far I have found Kernal#binding and Kernal#caller but I cant find out how to use
> |these to get
> |the information that I want, which is "Object, and method that instanciated me."
>
> Currently, no.  new caller interface is in RCR.
>
> |Q.3 given the code below is there a way to exit a call chain as follows
> |
> |all
> |a.nice.way.to.avoid.testing.for.nil.all.of.the.time
> |#I want to get <HERE> as fast as possible!
> |
> |at present my implementation of Null#method_missing returns self. This means that the
> |code above calls Null#method_missing on each "undefined message eating null" method
> |call, 11 times!
> |
> |what I was wondering is whether there is a way to jump from a.nice (implemented by
> |Null#method_missing) to <HERE> in a quick and elegant manner (i.e. like a throw catch
> |but without the semantics)
>
> Without using catch nor rescue?  No (Sorry for negative answers).
>
> But this is intersting.  If someone would come up with nice solution
> proposal, I'd like to consider implementing it (maybe).
>
>                                                         matz.

> ------------------------

#!/usr/bin/env ruby

#This is a first attempt at supporting the Null pattern in Ruby
#I couldnt find a detailed explanation of the Null pattern on the web
#so this is a cleanroom implementation and there are probably things
#I have forgotton

class Null
  attr_reader :name
  attr_reader :theCaller
  attr_reader :theBinding
  def initialize(aString)
    @name  String
    @theCaller  aller
    @theBinding  inding
  end
  def debug
    @debugue if !isDefaultNull?
    self
  end
  def isDefaultNull?
 self   NULL
  end
  def null?
    true
  end
  def nil?
    true
  end
  def  a )
    a.nil?
  end
  def new( *args )
 Null.new( *args )
  end

  def to_s
    return 'NULL' if isDefaultNull?
    'null' + @name
  end
  def method_missing( aSymbol, *args )
    puts("XX-" + theCaller.join("\n") + aSymbol.to_s + "-XX" ) if (@debug true)
    self
  end
  def respond_to?
    true
  end
  def hash
    nil.hash
  end

end

class Object
  def null?
    false
  end
end

#allows users to refer to "null"
#or a named null('Nemo')

NULLll.new

def null( *args )
  return(NULL) if (args.size 0)
  return(Null.new(*args))
end

#------------------------------------------------------
in

_Null.rb Contains tests for the Null class ßÅ require 'Lapidary/TestCase' require 'Null' #due to the wierd behaviour of Null it could be hard to test! class TC_Null < Lapidary::TestCase #Properties of Null: #there is a singleton use case #can have individual instances if desired #ignores unknown messages (instead of raising erros like nil). #collect data of the original receiver for debugging #easy for user to refer to similarly to 'nil' as 'null' #users reference def testThisNull assertBlock('null should be identical to NULL') { null NULL } assertEqual( null.name , '' ) assertEqual( null.to_s , 'null' ) end def testNULLnew myNull ULL.new puts myNull.theBinding.inspect assertEqual( myNull.theCaller , '' ) end def testNamedNull myNull ull('Eric') assertEqual( 'Eric', myNull.name ) assertEqual( 'nullEric', myNull.to_s ) end def testNullAbsorbsUndefinedMessages assertEqual( null, null.help.me.to.run.this.program.jimmy ) end def testNullGlobalIsSingleton tmpNullLL require 'Null' assertBlock { tmpNull NULL } end def testNullDebug assertEqual( null, null('Mine').debug.testing.one.two.three ) end end require 'Lapidary/UI/Console/TestRunner' Lapidary::UI::Console::TestRunner.run(TC_Null) --------------CC4D4D01074E3372F83EC9CB Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> Have you had any further thoughs on this matz? <p>as far as a "nice solution proposal", the only thing that I can suggest is that the special global object "null" is defined. <br>null would be an instance of class Null. <p>this allows a developer to use the global "null" or a user instanciated named "null" which may be is useful for debugging. <p>1. Instances of class Null, are handled specially by:&nbsp; if (condition) then ... else ... end and do not execute either the then or the else clauses. <br>2. Instances of class Null either simply implemetn method_missing to return null, or have some way to skip the call cahin as indicated in Q3 below. <p>I&nbsp;have appended some source code at&nbsp; the end of this email, which is far from final but works sufficiently to test the concepts out. <p>cheers <p>Keith <br>-------------------------------- <br>Yukihiro Matsumoto wrote: <blockquote TYPE¥¿TE>Hi, <p>In message "[ruby-talk:17721] Null Pattern" <br>&nbsp;&nbsp;&nbsp; on 01/07/12, Keith Hodges &lt;K.Hodges / ftel.co.uk> writes: <p>|Q.1 What is the best way to define a new global constant like "nil" (i.e. lowercase). <p>There's only one way: hack the parser.&nbsp; Pseudo variables: nil, false, <br>true, self, __FILE__, and __LINE__ are built in Ruby syntax. <p>|Q.2 I would like to be able to obtain information about the instanciator of aNull <br>|so far I have found Kernal#binding and Kernal#caller but I cant find out how to use <br>|these to get <br>|the information that I want, which is "Object, and method that instanciated me." <p>Currently, no.&nbsp; new caller interface is in RCR. <p>|Q.3 given the code below is there a way to exit a call chain as follows <br>| <br>|all <br>|a.nice.way.to.avoid.testing.for.nil.all.of.the.time <br>|#I want to get &lt;HERE> as fast as possible! <br>| <br>|at present my implementation of Null#method_missing returns self. This means that the <br>|code above calls Null#method_missing on each "undefined message eating null" method <br>|call, 11 times! <br>| <br>|what I was wondering is whether there is a way to jump from a.nice (implemented by <br>|Null#method_missing) to &lt;HERE> in a quick and elegant manner (i.e. like a throw catch <br>|but without the semantics) <p>Without using catch nor rescue?&nbsp; No (Sorry for negative answers). <p>But this is intersting.&nbsp; If someone would come up with nice solution <br>proposal, I'd like to consider implementing it (maybe). <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; matz.</blockquote> <blockquote TYPE¥¿TE>------------------------</blockquote> <tt><font size>#!/usr/bin/env ruby</font></tt><tt><font size></font></tt> <p><tt><font size>#This is a first attempt at supporting the Null pattern in Ruby</font></tt> <br><tt><font size>#I couldnt find a detailed explanation of the Null pattern on the web</font></tt> <br><tt><font size>#so this is a cleanroom implementation and there are probably things</font></tt> <br><tt><font size>#I have forgotton</font></tt><tt><font size></font></tt> <p><tt><font size>class Null</font></tt> <br><tt><font size>&nbsp; attr_reader :name</font></tt> <br><tt><font size>&nbsp; attr_reader :theCaller</font></tt> <br><tt><font size>&nbsp; attr_reader :theBinding</font></tt> <br><tt><font size>&nbsp; def initialize(aString)</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; @name String</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; @theCaller aller</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; @theBinding inding</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def debug</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; @debugue if !isDefaultNull?</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; self</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def isDefaultNull?</font></tt> <br><tt><font size>&nbsp;self&nbsp; NULL</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def null?</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; true</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def nil?</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; true</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def a )</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; a.nil?</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def new( *args )</font></tt> <br><tt><font size>&nbsp;Null.new( *args )</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp;</font></tt> <br><tt><font size>&nbsp; def to_s</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; return 'NULL' if isDefaultNull?</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; 'null' + @name</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def method_missing( aSymbol, *args )</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; puts("XX-" + theCaller.join("\n") + aSymbol.to_s + "-XX" ) if (@debug true)</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; self</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def respond_to?</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; true</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def hash</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; nil.hash</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp;</font></tt> <br><tt><font size>end</font></tt><tt><font size></font></tt> <p><tt><font size>class Object</font></tt> <br><tt><font size>&nbsp; def null?</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; false</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>end</font></tt><tt><font size></font></tt> <p><tt><font size>#allows users to refer to "null"</font></tt> <br><tt><font size>#or a named null('Nemo')</font></tt><tt><font size></font></tt> <p><tt><font size>NULLll.new</font></tt><tt><font size></font></tt> <p><tt><font size>def null( *args )</font></tt> <br><tt><font size>&nbsp; return(NULL) if (args.size 0)</font></tt> <br><tt><font size>&nbsp; return(Null.new(*args))</font></tt> <br><tt><font size>end</font></tt><tt><font size></font></tt> <p><tt><font size>#------------------------------------------------------</font></tt> <br><tt><font size>¥»gin</font></tt> <br><tt><font size>
_Null.rb</font></tt> <br><tt><font size>Contains tests for the Null class</font></tt> <br><tt><font size>ßÅ</font></tt><tt><font size></font></tt> <p><tt><font size>require 'Lapidary/TestCase'</font></tt> <br><tt><font size>require 'Null'</font></tt><tt><font size></font></tt> <p><tt><font size>#due to the wierd behaviour of Null it could be hard to test!</font></tt><tt><font size></font></tt> <p><tt><font size>class TC_Null &lt; Lapidary::TestCase</font></tt> <br><tt><font size>&nbsp;</font></tt> <br><tt><font size>#Properties of Null:</font></tt> <br><tt><font size>#there is a singleton use case</font></tt> <br><tt><font size>#can have individual instances if desired</font></tt> <br><tt><font size>#ignores unknown messages (instead of raising erros like nil).</font></tt> <br><tt><font size>#collect data of the original receiver for debugging</font></tt> <br><tt><font size>#easy for user to refer to similarly to 'nil' as 'null'</font></tt><tt><font size></font></tt> <p><tt><font size>#users reference</font></tt> <br><tt><font size>&nbsp; def testThisNull</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertBlock('null should be identical to NULL') { null &nbsp; NULL }</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertEqual( null.name , '' )</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertEqual( null.to_s , 'null' )</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def testNULLnew</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; myNull ULL.new</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; puts myNull.theBinding.inspect</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertEqual( myNull.theCaller , '' )</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def testNamedNull</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; myNull ull('Eric')</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertEqual( 'Eric', myNull.name )</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertEqual( 'nullEric', myNull.to_s )</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def testNullAbsorbsUndefinedMessages</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertEqual( null, null.help.me.to.run.this.program.jimmy )</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def testNullGlobalIsSingleton</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; tmpNullLL</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; require 'Null'</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertBlock { tmpNull NULL }</font></tt> <br><tt><font size>&nbsp; end</font></tt> <br><tt><font size>&nbsp; def testNullDebug</font></tt> <br><tt><font size>&nbsp;&nbsp;&nbsp; assertEqual( null, null('Mine').debug.testing.one.two.three )</font></tt> <br><tt><font size>&nbsp; end</font></tt><tt><font size></font></tt> <p><tt><font size>end</font></tt><tt><font size></font></tt> <p><tt><font size>require 'Lapidary/UI/Console/TestRunner'</font></tt> <br><tt><font size>Lapidary::UI::Console::TestRunner.run(TC_Null)</font></tt></html> --------------CC4D4D01074E3372F83EC9CB--