Dot versus double-colon

H

Hal Fulton

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

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

File::eek:pen(...)
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
 
M

Michael Garriss

Hal said:
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
 
M

Michael Garriss

Michael said:
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......
 
H

Hal Fulton

Michael said:
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
 
M

Michael Garriss

Hal said:
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
 
H

Hal Fulton

Michael said:
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
 
G

Gavin Sinclair

OK, I've been thinking (always dangerous after 11 pm).
Class-level entities can be accessed via a double-colon.
No big mystery:

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

But a constant can't:
File.SEPARATOR # syntax error
First, why is it this way?

File.open() is sending the message :eek:pen 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.

Cheers,
Gavin


(*) Classes *are* objects.
 
M

Michael Garriss

Hal said:
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
 
H

Hal Fulton

Gavin said:
File.open() is sending the message :eek:pen 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?
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?
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
 
G

Gavin Sinclair

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

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?
 
M

Mauricio Fernández

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

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 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, (e-mail address removed)
 
H

Hal Fulton

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

Well, I guess I'm just being a little irrational here.

I just happen to dislike :: in every case.

I think what I'm saying is not "make constants into methods"
but "make the notations the same (and disallow methods named
the same as constants)."

But it's unimportant and there are probably reasons for not
doing so.
The constant takes precedence over the method when using ::, so no
recursion.

Hmm. So if you *wanted* to recurse, you'd have to use the
dot notation.

Again it's only an issue because Ruby allows a class to have
a method and a constant by the same name.

Here's another thought question. Are all constants class-level?
Would a singleton constant attached to an object make sense?
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

Very good. I'd have seen that if I hadn't failed to see it.
How's that for a tautology?

Hal
 
H

Hal Fulton

Hal said:
Here's another thought question. Are all constants class-level?
Would a singleton constant attached to an object make sense?

To reply to myself:

3.instance_eval { FOO = 555 }
puts 3.instance_eval { FOO } # 555

So it's possible... even for a Fixnum, which can't have
singletons. :0

Useful or recommended? Not that I can imagine.

Hal
 
T

ts

H> 3.instance_eval { FOO = 555 }
H> puts 3.instance_eval { FOO } # 555

svg% ruby -e '3.instance_eval { FOO = 555 }; puts 12.instance_eval { FOO }'
555
svg%


Guy Decoux
 
H

Hal Fulton

ts said:
H> 3.instance_eval { FOO = 555 }
H> puts 3.instance_eval { FOO } # 555

svg% ruby -e '3.instance_eval { FOO = 555 }; puts 12.instance_eval { FOO }'
555
svg%

Thanks, Guy...

you.say(so_much) { without_using(any_English) }

Hal
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top