--------------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
> |
> |a ll
> |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
@debug ue 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')
NULL ll.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
tmpNull LL
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: 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 have appended some source code at 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> on 01/07/12, Keith Hodges <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. 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. 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>|a ll
<br>|a.nice.way.to.avoid.testing.for.nil.all.of.the.time
<br>|#I want to get <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 <HERE> in a quick and elegant manner (i.e.
like a throw catch
<br>|but without the semantics)
<p>Without using catch nor rescue? No (Sorry for negative answers).
<p>But this is intersting. If someone would come up with nice solution
<br>proposal, I'd like to consider implementing it (maybe).
<p>
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> attr_reader :name</font></tt>
<br><tt><font size> attr_reader :theCaller</font></tt>
<br><tt><font size> attr_reader :theBinding</font></tt>
<br><tt><font size> def initialize(aString )</font></tt>
<br><tt><font size> @name String</font></tt>
<br><tt><font size> @theCaller aller</font></tt>
<br><tt><font size> @theBinding inding</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def debug</font></tt>
<br><tt><font size> @debug ue if !isDefaultNull?</font></tt>
<br><tt><font size> self</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def isDefaultNull?</font></tt>
<br><tt><font size> self NULL</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def null?</font></tt>
<br><tt><font size> true</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def nil?</font></tt>
<br><tt><font size> true</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def a )</font></tt>
<br><tt><font size> a.nil?</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def new( *args )</font></tt>
<br><tt><font size> Null.new( *args )</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> </font></tt>
<br><tt><font size> def to_s</font></tt>
<br><tt><font size> return 'NULL' if isDefaultNull?</font></tt>
<br><tt><font size> 'null' + @name</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def method_missing( aSymbol, *args )</font></tt>
<br><tt><font size> puts("XX-" + theCaller.join("\n")
+ aSymbol.to_s + "-XX" ) if (@debug true)</font></tt>
<br><tt><font size> self</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def respond_to?</font></tt>
<br><tt><font size> true</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def hash</font></tt>
<br><tt><font size> nil.hash</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> </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> def null?</font></tt>
<br><tt><font size> false</font></tt>
<br><tt><font size> 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>NULL ll.new</font></tt><tt><font size></font></tt>
<p><tt><font size>def null( *args )</font></tt>
<br><tt><font size> return(NULL) if (args.size 0)</font></tt>
<br><tt><font size> 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 < Lapidary::TestCase</font></tt>
<br><tt><font size> </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> def testThisNull</font></tt>
<br><tt><font size> assertBlock('null should be identical
to NULL') { null NULL }</font></tt>
<br><tt><font size> assertEqual( null.name , '' )</font></tt>
<br><tt><font size> assertEqual( null.to_s , 'null'
)</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def testNULLnew</font></tt>
<br><tt><font size> myNull ULL.new</font></tt>
<br><tt><font size> puts myNull.theBinding.inspect</font></tt>
<br><tt><font size> assertEqual( myNull.theCaller
, '' )</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def testNamedNull</font></tt>
<br><tt><font size> myNull ull('Eric')</font></tt>
<br><tt><font size> assertEqual( 'Eric', myNull.name
)</font></tt>
<br><tt><font size> assertEqual( 'nullEric', myNull.to_s
)</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def testNullAbsorbsUndefinedMessages</font></tt>
<br><tt><font size> assertEqual( null, null.help.me.to.run.this.program.jimmy
)</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def testNullGlobalIsSingleton</font></tt>
<br><tt><font size> tmpNull LL</font></tt>
<br><tt><font size> require 'Null'</font></tt>
<br><tt><font size> assertBlock { tmpNull NULL
}</font></tt>
<br><tt><font size> end</font></tt>
<br><tt><font size> def testNullDebug</font></tt>
<br><tt><font size> assertEqual( null, null('Mine').debug.testing.one.two.three
)</font></tt>
<br><tt><font size> 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--