TL;DR - I agree with you, but others need convincing.
--------------
@dasch I tried to change this recently, and subsequently reverted in
8ba491a[1]. See discussion in aa1d1e4[2].
As you say, we have to deal with writer methods to make this work. My
implementation dealt with this by backporting public_send for 1.8.
However, the backport needed some more work and in any case would have
had performance difficulties I think.
It would be possible to do a special case for writer methods, but they
wouldn't be able to deal with more than one argument, without a backport
of public_send. IMO it would be best to just not let delegate work with
writer methods + multiple args (it's a very very edge case).
But anyway, given the opposition to this change (see discussion in the
commit linked) and the various complications with implementing it, I
lost interest and reverted.
By all means feel free to try to persuade people and suggest an
implementation, but I am just letting you know that I've already been
down the road and gave up ;)
[1]
https://github.com/rails/rails/commit/8ba491acc31bf08cf63a83ea0a3c314c52cd020f
[2]
https://github.com/rails/rails/commit/aa1d1e4962ba218f34defd0e7f0b665c795eb12b
--------------
I removed the ability in master, and deprecated it in 3-1-stable. If we
make this change, we do need to give people an upgrade path, so there
does need to be a deprecation before the change is actually made.
One feature of your implementation is that the following will not work:
class Foo
delegate :foo=, :to => :bar
end
foo.send(:foo=, 1, 2)
# => will do 'foo.bar.foo = 1', not 'foo.bar.send(:foo=, 1, 2)'
I think this is reasonable because this is a quite esoteric usage of a
writer method. However, we should raise ArgumentError if there are
multiple arguments in this case, and again we would need to provide a
deprecation.
I think checking args.length for writer methods should be performant
enough for the deprecation. Then, in the future implementation, we could
just define writer methods with no splat, so Ruby would take care of
raising the ArgumentError.
Jon
delegate is just a convenience method, a little utility that
1) saves the user from writing the delegation by hand
2) it is declarative, which is a plus in my view, intention is more clear
Since I can delegate to private methods, and delegate is just a macro,
I see no reason why it should impose any arbitrary restriction like
visibility. Conceptually.
That being said, if that was dropped for the benefit of performance,
I'd personally buy that. In order not to put a penalty on all calls,
you need to write your own wrappers for private methods. Sounds
reasonable to me.
@Xavier: I think users perceive `delegate` as a shorthand for:
def foo
@target.foo
end
and not
def foo
@target.__send__(:foo)
end
so I actually believe the proposed semantics more closely resembles
the perception. That's just my point of view, of course.
Yes, that's what I meant.
We need a patch against 3-1-stable that:
* Calls @target.foo, rescues NoMethodError, tries @target.__send__(:foo)
and if that works, shows a deprecation warning. (The reason for this
implementation is that there should be no performance hit in the public
case.)
* Shows a deprecation warning if args.length > 1 &&
method_name.ends_with?('=')
Then, we need the patch against master to just define def foo=(bar) (no
splat), when method_name.ends_with?('=').
If the deprecation in 3-1-stable is too involved, we might need to think
about deprecating in 3.2 and removing in 3.3. But let's see the code
first. Also note that this deprecation won't get into 3.1.0, so it would
be a new deprecation in 3.1.1. (Some may object to this, but I think
it's acceptable personally.)
> @Xavier: I think users perceive `delegate` as a shorthand for:
>
> def foo
> @target.foo
> end
>
> and not
>
> def foo
> @target.__send__(:foo)
> end
>
> so I actually believe the proposed semantics more closely resembles
> the perception. That's just my point of view, of course.
Yes, this is my perspective as well. To me the POLS is that 'delegate'
is a macro for the former, which does not support non-public methods.
The new version should play well with []= methods.
If the change is accepted I will be perfectly willing to implement a
deprecation patch for 3.1. Should I begin now, or is the issue still
contested?
Cheers,
Daniel Schierbeck
--
Med venlig hilsen
Daniel Schierbeck
target.method=(*args, &block)
throws a syntax error. I'll keep working on it.
On Mon, Aug 29, 2011 at 2:42 PM, Jon Leighton <j...@jonathanleighton.com> wrote:
--
Comments are welcome - the code can be tricky.
3. `*args` contraction (we must build an array that is just GC'd)
4. Splatting the args back to the `__send__`
As you say, this would complicate things quite a bit. What happens
when the specified arity is wrong?