[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Dot versus double-colon

Hal E. Fulton

9/14/2003 5:05:00 AM

OK, I've been thinking (always dangerous after 11 pm).

Class-level entities can be accessed via a double-colon.
No big mystery:

File::open(...)
File::SEPARATOR

Happily, a class method can also be accessed via a dot:

File.open(...)

But a constant can't:

File.SEPARATOR # syntax error

First, why is it this way?

Personally, I don't like the :: anyway, as it reminds me
of C++.

By the way, for those who are wondering, this *is* possible:

class File
def self.SEPARATOR
File::SEPARATOR
end
end

File.SEPARATOR # "/"

Even though it looks almost like recursion. Hmm, that raises
the question of why/how this works.

And another issue is: One *could* write a little module that,
when included in a class, exposed all the class's constants in
this way. Within five minutes I had it "almost" working. I'll
bet someone in another timezone or with more caffeine could
have it working in three. Anyone?

Hal


15 Answers

mgarriss

9/14/2003 5:34:00 AM

0

Hal Fulton wrote:

> Even though it looks almost like recursion. Hmm, that raises
> the question of why/how this works.
>
> And another issue is: One *could* write a little module that,
> when included in a class, exposed all the class''s constants in
> this way. Within five minutes I had it "almost" working. I''ll
> bet someone in another timezone or with more caffeine could
> have it working in three. Anyone?
>
> Hal


module Dot
def Dot.append_features( mod )
mod.constants.each{|c| mod.class_eval( "def self.#{c}() #{mod}::#{c}
end" ) }
end
end

Hmm....you''re right, it is late and this isn''t well tested.

Michael




mgarriss

9/14/2003 5:41:00 AM

0

Michael Garriss wrote:

> Hal Fulton wrote:
>
>> Even though it looks almost like recursion. Hmm, that raises
>> the question of why/how this works.
>>
>> And another issue is: One *could* write a little module that,
>> when included in a class, exposed all the class''s constants in
>> this way. Within five minutes I had it "almost" working. I''ll
>> bet someone in another timezone or with more caffeine could
>> have it working in three. Anyone?
>>
>> Hal
>
>
>
> module Dot
> def Dot.append_features( mod )
> mod.constants.each{|c| mod.class_eval( "def self.#{c}()
> #{mod}::#{c} end" ) }
> end
> end
>

Has to be included after all consts are defined......working on that......


Hal E. Fulton

9/14/2003 5:44:00 AM

0

Michael Garriss wrote:
> Michael Garriss wrote:
>
>> Hal Fulton wrote:
>>
>>> Even though it looks almost like recursion. Hmm, that raises
>>> the question of why/how this works.
>>>
>>> And another issue is: One *could* write a little module that,
>>> when included in a class, exposed all the class''s constants in
>>> this way. Within five minutes I had it "almost" working. I''ll
>>> bet someone in another timezone or with more caffeine could
>>> have it working in three. Anyone?
>>>
>>> Hal
>>
>>
>>
>>
>> module Dot
>> def Dot.append_features( mod )
>> mod.constants.each{|c| mod.class_eval( "def self.#{c}()
>> #{mod}::#{c} end" ) }
>> end
>> end
>>
>
> Has to be included after all consts are defined......working on that......

constant_added might help. and fyi, I was trying to use
define_method rather than eval''ing a string. wonder if
the techniques are interchangeable?

I''ll worry about it in the morning.

Hal


mgarriss

9/14/2003 5:54:00 AM

0

Hal Fulton wrote:

> Michael Garriss wrote:
>
>> Michael Garriss wrote:
>>
>>> Hal Fulton wrote:
>>>
>>>> Even though it looks almost like recursion. Hmm, that raises
>>>> the question of why/how this works.
>>>>
>>>> And another issue is: One *could* write a little module that,
>>>> when included in a class, exposed all the class''s constants in
>>>> this way. Within five minutes I had it "almost" working. I''ll
>>>> bet someone in another timezone or with more caffeine could
>>>> have it working in three. Anyone?
>>>>
>>>> Hal
>>>
>>>
>>>
>>>
>>>
>>> module Dot
>>> def Dot.append_features( mod )
>>> mod.constants.each{|c| mod.class_eval( "def self.#{c}()
>>> #{mod}::#{c} end" ) }
>>> end
>>> end
>>>
>>
>> Has to be included after all consts are defined......working on
>> that......
>
>
> constant_added might help. and fyi, I was trying to use
> define_method rather than eval''ing a string. wonder if
> the techniques are interchangeable?
>

Not sure. For some reason I never use #define_method. I tend to get a
little #eval happy sometimes. It was just so exicting when I learned
about #eval that I have trouble putting it down. I''ll have to add
#define_method (and #constant_added for that matter) to my bag ''o tricks.

Michael


Hal E. Fulton

9/14/2003 5:59:00 AM

0

Michael Garriss wrote:
> Hal Fulton wrote:
>
>> Michael Garriss wrote:
>>
>>> Michael Garriss wrote:
>>>
>>>> Hal Fulton wrote:
>>>>
>>>>> Even though it looks almost like recursion. Hmm, that raises
>>>>> the question of why/how this works.
>>>>>
>>>>> And another issue is: One *could* write a little module that,
>>>>> when included in a class, exposed all the class''s constants in
>>>>> this way. Within five minutes I had it "almost" working. I''ll
>>>>> bet someone in another timezone or with more caffeine could
>>>>> have it working in three. Anyone?
>>>>>
>>>>> Hal
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> module Dot
>>>> def Dot.append_features( mod )
>>>> mod.constants.each{|c| mod.class_eval( "def self.#{c}()
>>>> #{mod}::#{c} end" ) }
>>>> end
>>>> end
>>>>
>>>
>>> Has to be included after all consts are defined......working on
>>> that......
>>
>>
>>
>> constant_added might help. and fyi, I was trying to use
>> define_method rather than eval''ing a string. wonder if
>> the techniques are interchangeable?
>>
>
> Not sure. For some reason I never use #define_method. I tend to get a
> little #eval happy sometimes. It was just so exicting when I learned
> about #eval that I have trouble putting it down. I''ll have to add
> #define_method (and #constant_added for that matter) to my bag ''o tricks.

I think I meant constant_missing. Hmm, *is* there a constant_added??? If
not, maybe there should be.

But constant_missing might not be useful here. My brain is *really*
getting cloudy now.

I''m the same way. I''ve overused eval in the past (by some people''s
standards). But now we''ve got const_[gs]et, instance_variable_[gs]et,
define_method, and all that coolness. These often obviate the need
for eval.

Hal


Gavin Sinclair

9/14/2003 6:05:00 AM

0

On Sunday, September 14, 2003, 3:04:40 PM, Hal wrote:

> OK, I''ve been thinking (always dangerous after 11 pm).

> Class-level entities can be accessed via a double-colon.
> No big mystery:

> File::open(...)
> File::SEPARATOR

> Happily, a class method can also be accessed via a dot:

> File.open(...)

> But a constant can''t:

> File.SEPARATOR # syntax error

> First, why is it this way?

File.open() is sending the message :open to object File. The same
cannot be said for the constant SEPARATOR.


> Personally, I don''t like the :: anyway, as it reminds me
> of C++.

I don''t like :: for methods, because . makes sense for method calls on
objects *and* classes, because .... well, you know why (*).

:: makes sense for namespaces - as in constant resolution. It would
not bother me one bit should :: be deprecated for method calls.


> By the way, for those who are wondering, this *is* possible:

> class File
> def self.SEPARATOR
> File::SEPARATOR
> end
> end

> File.SEPARATOR # "/"

> Even though it looks almost like recursion. Hmm, that raises
> the question of why/how this works.

I''m sure you realise now. It''s because you''ve defined a method :)


> And another issue is: One *could* write a little module that,
> when included in a class, exposed all the class''s constants in
> this way. Within five minutes I had it "almost" working. I''ll
> bet someone in another timezone or with more caffeine could
> have it working in three. Anyone?

I''m happy for methods and constants to be accessed via different
mechanisms (message passing vs namespace resolution) and for those
mechanisms to be syntactically distinct.

> Hal

Cheers,
Gavin


(*) Classes *are* objects.


mgarriss

9/14/2003 6:05:00 AM

0


Hal Fulton wrote:

> I think I meant constant_missing. Hmm, *is* there a constant_added??? If
> not, maybe there should be.
>
> But constant_missing might not be useful here. My brain is *really*
> getting cloudy now.
>
> I''m the same way. I''ve overused eval in the past (by some people''s
> standards). But now we''ve got const_[gs]et, instance_variable_[gs]et,
> define_method, and all that coolness. These often obviate the need
> for eval.
>

Just had to share this super ugly example from some of my #eval happy code:

def add_cols( *mods )
eval(<<CODE
class << self
[#{mods.join('','')}].each do |mod|
name = mod.to_s.sub(''Rextra::DB::Col::'','''')
eval(eval("Rextra::DB::Col.new_col(name,eval(\\"\#{mod}::NEW_COL\\"
))"))
end
def new( *args )
obj = super( *args )
methods.each do |m|
method(m).call(obj) if m =~ /^__new_col_/
end
obj
end
end
CODE
)
end


Check out the four layers deep eval. Don''t ask......

Michael


Hal E. Fulton

9/14/2003 7:13:00 AM

0

Gavin Sinclair wrote:
>>First, why is it this way?
>
> File.open() is sending the message :open to object File. The same
> cannot be said for the constant SEPARATOR.

Certainly it could be said. In fact, there is no way to tell
by looking at it whether it is in fact a method or a constant.

And a constant could be viewed as a method that always returns
the same value. Uniform access, you know.

> :: makes sense for namespaces - as in constant resolution. It would
> not bother me one bit should :: be deprecated for method calls.

I''m accessing a value within an object. Sure, the value
happens to be constant. So what?

>
>>By the way, for those who are wondering, this *is* possible:
>
>
>> class File
>> def self.SEPARATOR
>> File::SEPARATOR
>> end
>> end
>
>
>> File.SEPARATOR # "/"
>
>
>>Even though it looks almost like recursion. Hmm, that raises
>>the question of why/how this works.
>
> I''m sure you realise now. It''s because you''ve defined a method :)

You missed my point. Since the method File.SEPARATOR can be referred
to by the syntax File::SEPARATOR, then how does the method know that
it is not calling itself recursively?

>>And another issue is: One *could* write a little module that,
>>when included in a class, exposed all the class''s constants in
>>this way. Within five minutes I had it "almost" working. I''ll
>>bet someone in another timezone or with more caffeine could
>>have it working in three. Anyone?
>
>
> I''m happy for methods and constants to be accessed via different
> mechanisms (message passing vs namespace resolution) and for those
> mechanisms to be syntactically distinct.

I see what you mean. But I say: Why should a constant be anything
but a reader which happens always to return the same value?

Hal


Gavin Sinclair

9/14/2003 8:05:00 AM

0

On Sunday, September 14, 2003, 5:13:04 PM, Hal wrote:

> Gavin Sinclair wrote:
>>>First, why is it this way?
>>
>> File.open() is sending the message :open to object File. The same
>> cannot be said for the constant SEPARATOR.

> Certainly it could be said. In fact, there is no way to tell
> by looking at it whether it is in fact a method or a constant.

It "could" be said, but it can''t. The interpreter knows whether it''s
a constant, and the capital letter is more than just a convention as
well - even though SEPERATOR is a valid method name.

> And a constant could be viewed as a method that always returns
> the same value. Uniform access, you know.

Yes, it''s appealing. Sometimes I implement "constants" as methods,
because I want the return value to be regenerated each time. If a
constant is a hash, its innards can be modified, and it ain''t so
constant anymore. I suppose there''s :freeze...

So your statement above should be qualified: the constant would be a
method that always returns the same object, not neccesarily the same
value.

>> :: makes sense for namespaces - as in constant resolution. It would
>> not bother me one bit should :: be deprecated for method calls.

> I''m accessing a value within an object. Sure, the value
> happens to be constant. So what?

Sending a message is very different from accessing a value. I
acknowledge your intentions, though I''m happy the way things are, but
that fundamental needs to be kept in mind, IMO.

Just like attr_* are convenient sugar for literal accessor methods,
are you proposing that "CONSTANT = 1" could/should be sugar for
creating a method?


>>
>>>By the way, for those who are wondering, this *is* possible:
>>
>>
>>> class File
>>> def self.SEPARATOR
>>> File::SEPARATOR
>>> end
>>> end
>>
>>
>>> File.SEPARATOR # "/"
>>
>>
>>>Even though it looks almost like recursion. Hmm, that raises
>>>the question of why/how this works.
>>
>> I''m sure you realise now. It''s because you''ve defined a method :)

> You missed my point. Since the method File.SEPARATOR can be referred
> to by the syntax File::SEPARATOR, then how does the method know that
> it is not calling itself recursively?

Presumably the interpreter looks for a constant before a method. This
may be good luck rather than good management, although the :: may have
something to do with it.

> [...]

Cheers,
Gavin

BTW, you could make constants available through dot-notation using
:method_missing, couldn''t you?


Mauricio Fernández

9/14/2003 8:48:00 AM

0

On Sun, Sep 14, 2003 at 04:13:04PM +0900, Hal Fulton wrote:
> And a constant could be viewed as a method that always returns
> the same value. Uniform access, you know.

The problem you identified (infinite recursion) justifies the existence
of ::. Moreover, :: should be somewhat faster than a normal method
dispatch.

> >:: makes sense for namespaces - as in constant resolution. It would
> >not bother me one bit should :: be deprecated for method calls.
>
> I''m accessing a value within an object. Sure, the value
> happens to be constant. So what?

I agree w/ Gavin here, I''d be happy to drop the
SomeClass::singleton_method notation.

> >>By the way, for those who are wondering, this *is* possible:
> >
> >
> >> class File
> >> def self.SEPARATOR
> >> File::SEPARATOR
> >> end
> >> end
> >
> >
> >> File.SEPARATOR # "/"
> >
> >
> >>Even though it looks almost like recursion. Hmm, that raises
> >>the question of why/how this works.
> >
> >I''m sure you realise now. It''s because you''ve defined a method :)
>
> You missed my point. Since the method File.SEPARATOR can be referred
> to by the syntax File::SEPARATOR, then how does the method know that
> it is not calling itself recursively?

The constant takes precedence over the method when using ::, so no
recursion.

> >>And another issue is: One *could* write a little module that,
> >>when included in a class, exposed all the class''s constants in
> >>this way. Within five minutes I had it "almost" working. I''ll
> >>bet someone in another timezone or with more caffeine could
> >>have it working in three. Anyone?

There''s a really obvious possible solution:

batsman@tux-chan:/tmp$ expand -t2 i.rb

if nil

class Module
alias_method :_old_method_missing, :method_missing
def method_missing(meth, *args, &block)
return const_get(meth) if const_defined? meth
_old_method_missing
end
end

end

# or

module ExposeConstants
def self.extend_object(mod)
class << mod;
alias_method :_old_method_missing, :method_missing
end
super
end

def method_missing(meth, *args, &block)
return const_get(meth) if const_defined? meth
_old_method_missing
end
end

File.extend ExposeConstants

p File.SEPARATOR

batsman@tux-chan:/tmp$ ruby i.rb
"/"

Using method_missing has the following properties:
* works for constants defined after .extend
* it''s much slower than defining methods for the existent constants
(that''s easy to write too).

> >I''m happy for methods and constants to be accessed via different
> >mechanisms (message passing vs namespace resolution) and for those
> >mechanisms to be syntactically distinct.
>
> I see what you mean. But I say: Why should a constant be anything
> but a reader which happens always to return the same value?

Speed? It isn''t probably the primary reason, however.

Another benefit is that Ruby can give you a better warning if you redefine
a constant (you''ll get warning: method redefined; discarding old Constant
in the other case).

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| ''_ \ / _` | __/ __| ''_ ` _ \ / _` | ''_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

We come to bury DOS, not to praise it.
-- Paul Vojta, vojta@math.berkeley.edu