[suby-talk] "Is" and ideas for moving foward
Peter Vanbroekhoven
calamitas at advalvas.be
Sat Sep 24 18:18:17 EDT 2005
On Sat, 24 Sep 2005, TRANS wrote:
> Today George of Nitro asked me to alias #include to #is:
>
> class Foo
> is Bar
> end
I like this too. It's very nice for things like Enumerable:
class Foo
is Enumerable
end
If the name of a module is a noun, #is_a and #is_an are nice to. And if
you're afraid of people accidentally overriding these methods, you can
also alias it to #walks_and_quacks_like_a ;-) Actually, I'm not completely
joking about this, it is one of those nice details that can make code more
fun to read!
> I like it and saw no ready reason now to support it so I added it to
> Nano. This got me to thinking about how modules are included. I really
> tire of jumping through hoops using Module#included to tell it I want
> class method included too. The use of #extend seems backward --why
> should the class dictate how the module effect it? (except under
> special circumstances). I think that undermines the whole idea of
> "enpsulated module".
>
> So I propose we get on with it and offer some declarations:
>
> module M
> function
> def f ; "F" ; end
> extends
> def x ; "X" ; end
> inherits
> def y ; "Y" ; end
> end
>
> 'function' is the same as current module_function and would be the
> default. It both acts as a non-extending module function and an
> instance-level inheritable. So,
>
> M.f #=> "F"
> M.x #=> error
> M.y #=> error
>
> class X
> is M
> end
>
> X.x #=> "X"
> X.new.y #=> "Y"
> X.f #=> error
> X.new.f #=> "F" (albeit it is private)
You know, maybe we can look at this slightly differently. At the moment,
this works:
class A
def x ; "x" ; end
def self.y ; "y" ; end
end
class B < A ; end
A.new.x
A.y
B.new.x
B.y
Why does this work? Because this is true:
B.is_a? A.metaclass
What does this mean? It means that B's metaclass is a subclass of A's
metaclass, although they've tried to cover up this fact. For example
B.metaclass.superclass will return Class.metaclass and not A.metaclass,
but A.metaclass is there in the chain. (You should remember that picture).
Now why oh why is the same thing not done on module inclusion? It seems to
make sense to do it, right? And it would solve part of your problem. Of
course it is not as powerful as your proposal above, but it goes part of
the way and is simpler, so I say do it like that and build extra
functionality on top of that.
Also, if you want to go the above way, please let these new functions have
block forms too, or only block forms as far as I'm concerned. I find the
way things are now for private and all too magical, and also emacs will
indent better. So IMO the above would look better like this:
module M
function {
def f ; "F" ; end
}
extends {
def x ; "X" ; end
}
inherits {
def y ; "Y" ; end
}
end
Sure it adds a few more lines, but I find this a lot clearer.
> Also I would like to move foward on ultimately replacing the #methods
> and #instance_methods to take symbol query parameters, instead of have
> all the other methods: public_methods, private_methods, etc. In fact
> if methods tool on more of a 1st class role (even if faked). Then
> perhaps:
>
> M.methods.select { |m| m.access == :private }
>
> Of course I still am interesed in throwing out the current
> private/protected/public for now and start fresh later with a truer
> form.
Well, I think it would still be nice for public_methods etc to remain, but
just add a deneral select method (possibly even just as Module#methods).
The reason is that IMO these are still generally useful methods. I usually
only need either public_methods, or private_methods, or
public_instance_methods, and it makes little sense to all of a sudden have
to write twice as much code to do the same thing.
> Finally, I'm curious. And I know this might seem like a shocker. But I
> often wonder about the fact the #alias doesn't need a comma separated
> list of arguments. I know it's special but I wonder if it might be
> generally applicable?
>
> class X
> def intialize( a b c )
> #...
> end
> end
>
> X.new :A :B :C
Well, it causes ambiguity. "a b c d" can be parsed as follows:
a(b(c(d)))
a(b(c,d))
a(b(c),d)
a(b,c(d))
a(b,c,d)
Of course, if you don't want commas, you could always employ a Lispy kind
of syntax:
(X.new :A :B :C)
Or else require brackets around the parameters at all times:
X.new(:A :B :C)
I don't think you can get away with dropping these commas without
introducing extra brackets, or some other way of disambiguating thing.
Peter
More information about the suby-talk
mailing list