In message “Re: auto assign arguments?”
on Sat, 20 Jan 2007 01:58:06 +0900, “David C.” [email protected] writes:
|Would you mind providing a brief explanation of your objection? There
|is no Reason for rejection with the old RCR
|(http://oldrcrs.rubypal.com/rejected.html#rcr3) and it would be
|helpful to me (and I’m sure others) to understand why you think this
|is a bad idea.
I thought (and I still think) it is a good idea to separate method
argument and assignment in general. It’s convention supported by most
languages, and mixing parameters and assignments gives me impression
of toy-language.
Besides that, I think formal arguments of a method (including their
names) can be seen as part of class API. Allowing instance variables
as formal arguments seems like disclosing the internal issues.
Finally, I admit that the code like this
def initialize(@length)
end
is longer than
def initialize(length) @length = length
end
but I feel the intention of the latter code is far clearer than the
former.
just would be a willful disclosure a little bit like
attr_writer :length
Thinking about this some more - I wasn’t proposing this become part of
the API. Nor would I want to see this anywhere besides the
initializer. The proposal is that for initializers (only) you could
Ah I see here we are really diverging. Are you aware that you propose
different formal parameter symantics based on
the method name?
OTOH #initialize is a special method of course. But I am against it,
would
make the language more complicated.
If this were allowed, there would be no need to expose the @ in RDoc.
RDoc could be tweaked to hide that, so you’d still just see:
Again I fail to agree :(.
If you exposed an instance variable like that would it not be desired
for
RDoc to document this?
new(length)
Note that RDoc is already hiding initialize (as an instance method)
and showing you new (as a class method), so this would just be an
addition to that transformation.
So the proposed sugar would only be exposed to the intialize method
and anybody (human or machine) reading the class definition.
One thing I’d love to see in a future version of ruby is this;
def initialize(@thing, @other)
end
… and have that automagically initialize @thing and @other with the
submitted values.
Some thinking-out-loud:
#!/usr/bin/env ruby -w
class Module
def constructor(*attrs)
define_method(:initialize) do |*passed|
raise ArgumentError, “Wrong number of arguments”
unless attrs.size == passed.size
attrs.each_with_index do |att, i|
instance_variable_set("@#{att}", passed[i])
end
after_initialize if respond_to? :after_initialize
end
end
end
class ABC
constructor :a, :b, :c
def after_initialize
p instance_variables.map { |var| [var, instance_variable_get
(var)] }.sort
end
end
ABC.new(1, :two, “three”)
ABC.new(*%w[testing my code])
Besides that, I think formal arguments of a method (including their
Thinking about this some more - I wasn’t proposing this become part of
the API. Nor would I want to see this anywhere besides the
initializer. The proposal is that for initializers (only) you could
define (not reference pre-existing) instance variables:
def initialize(@length)
end
If this were allowed, there would be no need to expose the @ in RDoc.
RDoc could be tweaked to hide that, so you’d still just see:
new(length)
Note that RDoc is already hiding initialize (as an instance method)
and showing you new (as a class method), so this would just be an
addition to that transformation.
So the proposed sugar would only be exposed to the intialize method
and anybody (human or machine) reading the class definition.
|I feel that this is worth another shot, maybe Matz could tell us to stop
|working on this if he really does not like it.
|It seems reasonable to assume that the reasons he had to reject the RCR do
|not exist anymore or that he has changed his mind, no?
I haven’t changed my mind (yet). And I even disallowed above code in
1.9. Block parameters should only be local variables (and they are
effective only inside the block).
Matz,
Thank you for weighing in on this discussion (and, this being the
first time I’ve addressed you directly, thanks for this beautiful
language).
Would you mind providing a brief explanation of your objection? There
is no Reason for rejection with the old RCR
(http://oldrcrs.rubypal.com/rejected.html#rcr3) and it would be
helpful to me (and I’m sure others) to understand why you think this
is a bad idea.
Heck, why not
take this a step further and create automatic getters and setters? You
can always undef or redefine them.
I would really be against that. If you do that, there’s no point in
how Ruby currently has all instance data as private. It blows
encapsulation wide open and being very against the spirit of OO just
doesn’t feel Rubyish to me.
created and initialized with the submitted value. So: http://oldrcrs.rubypal.com/rejected.html#rcr3
Hm, no reason given, but one of the things I don’t like about it is the
change in syntax it required. With the advent of keyword parameters
(right?), and the ability to get the parameter names from within a
method, this should be trivial to implement on our own in 1.9 if Matz
doesn’t want it as the default behavior.
Heck, why not
take this a step further and create automatic getters and setters? You
can always undef or redefine them.
I would really be against that. If you do that, there’s no point in
how Ruby currently has all instance data as private. It blows
encapsulation wide open and being very against the spirit of OO just
doesn’t feel Rubyish to me.
Hm, you’re probably right.
I suppose it would require some fundamental changes to the language,
i.e. not allowing instance data to be set directly outside of the
constructor (forcing you to use the actual getter and setter methods
outside of the constructor). This is what Fortress does, and I think
it’s what Perl 6 will do as well.
I’m not sure what the downside of that change would be, other than a
forced method lookup. I don’t know enough about Ruby internals to know
if “@foo = 1” is cheaper than “foo = 1”, but I’m guessing that it is.
Forgive me, for I have been tainted by the Fortress language recently.
I thought (and I still think) it is a good idea to separate method
argument and assignment in general. It’s convention supported by most
languages, and mixing parameters and assignments gives me impression
of toy-language.
That’s interesting. Would you mind sharing your insight on why these
should be
separated? To me they seem similar enough to be “merged”. I think the
only
reason to separate them is because, at the machine-language level,
function
arguments are PUSHed onto the stack while assignments are MOVed to
memory. So
historically they come from different mechanisms. But if we agree that
computer
languages should be designed for humans, not computers, it seems more
natural to
view parameters as a specialized case of assignment.
Besides that, I think formal arguments of a method (including their
names) can be seen as part of class API. Allowing instance variables
as formal arguments seems like disclosing the internal issues.
I can see the number of arguments (and in other languages, their type)
as part
of the class API, but not their names since those variables’ names are
local to
the method. True, rdoc exposes those internals in the documentation, but
then it
also exposes the instance variables & methods used for default values.
For
consistency I think instance variables should be allowed as parameters
since
they are allowed as default values. But I acknowledge that consistency
may not
be the most important factor to consider here.
I dunno, forbidding instance variables may be the more “correct”
approach but I
think allowing them would be more useful. One of the reasons I like ruby
is
because it favors usefulness over strict “correctness” (e.g. you can
still get
to private methods if you really need it)
One thing I’d love to see in a future version of ruby is this;
def initialize(@thing, @other)
end
… and have that automagically initialize @thing and @other with the
submitted values.
I could have sworn Paul B. did this as part of RubyTreasures, but
I don’t see any such thing mentioned in the docs. I know it’s been
done somewhere as a language hack.
Personally, I think it ought to be the default behavior, since it’s
what you want about 80% of the time in practice I think. At worst,
you’ve got a couple of useless instance variables that people would
have to go to pains to get at via instance_variable_get. Heck, why not
take this a step further and create automatic getters and setters? You
can always undef or redefine them.