in reply to Re^3: Solving the SUPER problem in Mixins with a Dispatch Method
in thread Solving the SUPER problem in Mixins with a Dispatch Method

The problem with choosing the right names is that it requires some sort of psychic ability to foresee the clashes that might happen. It also leads to long method names even when there is no danger of ambiguity. For example inside the method Footballer::TakePenalty we shouldn't have to say shootBall because no other form of shooting makes sense in this context.

Namespaces are an inherently more powerful and general way of disambiguating and allow solutions that are simply not possible when you just make longer and longer names instead.

That is why we have packages and functions like Data::Dumper::Dumper() not data_dumper_dumper()

Without namespaces, calling a method is like asking for an action where the implementation and the entire meaning of the action is left to the object - so basically you are just hoping that you and the object both have the same vocabulary. With namespaces, only the implementation is left up to the object, the meaning of the method call is open to interpretation.

So for example, assuming that all the format() methods have been implemented correctly, not using namespaces means that you could end up with a formatted disk when you really wanted a formatted string. If namespaces are available then there can never be any such nasty accidents. A more real example of the dangers of allowing the object to supply not just the implementation but the meaning.

use IO::All; my $file = io("somefile"); log(5, $file, "some error"); sub log { my ($file, $level, $message) = @_; $file->print($message) if $level < $DEBUG_LEVEL; }
Getting the arguments swapped causes us to silently record rubbish into our log because IO::All changes not just the implementation but the entire meaning of <.

I think the reason this hasn't been implemented yet it because we get quite a bit of disambiguation by looking at the object on which the method is called. However sometimes that's not enough - mixins being a prime example.

Aliasing is a horrible hack and breaks genericity - if the method no longer has the correct name then you cannot pass that object into a generic function and expect it work.

As for unreal examples, yes, they're easy to create but real examples to exist. Where I really missed MI recently was when implementing a DB layer in Object Pascal. I needed to implement objects which were essentially cursors and allowed you access to the fields of the current row. I had to implement 3 types, one for ADO, one talking directly to ODBC and another talking to SQLite. So I inherited various bits from a base class and had 3 specialised subclasses, one for each target. The problem is that there are various behaviours of cursors that are orthogonal. They can be forward-only or random access cursors, updateable or read only. Mixins would have allowed me to bolt on these behaviours to the existing classes. I had to use delegation for the updateable vs readonly and I ended up having to write lots of boilerplate delegation methods. For the forward only situation I ended up putting the shared code into the base class and so there was no distinction at a class level between forward only and random access. This meant that I had to wait until run time to catch people trying to go backwards with a forward only cursor. If I had made them separate classes, these errors would have been caught at compile time but using delegation to do that was too fiddly to be worth it.

Delegation causes code like this

package Thingy; sub method { my $self = shift; $self->del->method($self, @_); } pakage Delegate; sub method { my $self = shift; my $parent = shift; # in here we completely ignore $self and do # lots of manipulation of $parent }
which is just plain wrong. Even if you can autogenerate the first method the second method should make you exceedngly worried because it completely ignores $self and spends all it's time poking around inside $parent. It is crying out to be a method in Thingy rather than in Delegate.
The upshot of this process is, that gazillions of hooks, stubs and extra layers are added in just incase. And experience shows that they rarely get used.

I don't think this is anything to do with delegation or mixins, this is simply trying to stuff too much into a single class and can happen by either method.

Can you point out anything specific that is dangerous or unworkable when using mixins along with namespaced-methods?

We are getting mixins in Perl 6 (via something like traits). I think the apocalypse, the exegesis (if it's out) and that paper will demonstrate their usefulness. Unfortunately I think we are getting at some of their bad points too.