It seems that a best practice would quickly arise in which any overloading of the smartmatch operator would perform a smartmatch evaluation with the other operand and a simpler representation of the current object. This way, if both lhs and rhs of a smartmatch are objects, they both get an opportunity to boil themselves down with their own simpler representations with the least amount of code necessary. If we recommend this approach, then putting the object overloads at the top of the table is the most sensible thing to do. David On Aug 22, 2012 6:36 PM, "Damian Conway" <damian@conway.org> wrote: > Robert Sedlacek wrote: > > > Do you have any specific use-case for bidirectional overload acceptance? > > No. Just a lot of (bad) experience with both OO code and code that > extends existing behaviours. > > The point here is simply that, when we allow new types (represented by > objects) > to be included in the smartmatching system, then it should be up to those > new > types to *fully* determine how they interact with that system. > > In other words, if you build a class, and if that class overloads ~~, > then it's important that the overloading predictably take control of > *every* smartmatch involving objects of the class. Because only the > class itself can know what smartmatching semantics make sense for its > objects (regardless of which side of the smartmatch they appear), and > hence determine how smartmatching should be implemented when one of its > objects is involved. > > > > I can see how this would be useful for some object types. But it also > > might make certain other cases impossible. > > I don't believe it would make any cases impossible. > > If you're overloading ~~ for the class, you handle every case in the > overloading. > If you're not overloading ~~ for the class, the issue doesn't arise is the > first place, since smartmatching falls back on the rest of the table. > > > > Say I have an object representing a type itself: > > > > 23 ~~ $IntType > > $IntType ~~ 23 > > > > I'd find it odd if that would work, but won't if I represent the type > > check as a code reference. > > But it *would*: you'd just write the ~~-overloading method for your TypeObj > class in such a way that it handles coderefs the way you want. If you want > the standard smartmatching behaviour (i.e. pass the TypeObj to the sub) > you'd implement it like so: > > package TypeObj; > > use overload > '~~' => sub { > my ($type_object, $comparand, $reversed) = @_; > > # What are we smartmatching against... > my $comparand_type = ref $comparand; > > # If it's a subref, pass the typeobj to the sub... > if ($comparand_type eq 'CODE') { > return $comparand->($type_object); > } > else { > return $comparand_type eq $type_object->type; > } > }; > > But if you want it to match against a code ref the same way it matches > against a number (i.e. is this other operand of the correct type?), > you'd implement it like this instead: > > package TypeObj; > > use overload > '~~' => sub { > my ($type_object, $comparand, $reversed) = @_; > > return ref($comparand_type) eq $type_object->type; > }; > > That's the entire point: if you overload ~~, then you get to (and have to) > decide the behaviour for all cases involving that class. > > > > Also, I wouldn't be able to match the object > > itself, right? For example: > > > > $IntType ~~ sub { ... } > > > > would ask the object on the left to match, but not the code reference > > No. It would call the overloaded ~~ on the Type object, which would then > decide how to handle that smartmatch (as in the examples above). > > > > This also means that an externally passed object could, unintentionally, > > change the meaning of my given/when constructs. > > Yes. But that is *always* the case, for any operation involving objects > with overloaded operators. > > > > Is it maybe possible to have separate overloads for 'smartmatcher' and > > 'smartmatchee' (couldn't find better terms right now)? > > You *can* have that: you just implement the overloading so as to check > whether it was passed the extra 'reversed' argument, and then do > whatever you want in either branch: > > package TypeObj; > > use overload > '~~' => sub { > my ($object, $other_operand, $reversed) = @_; > > if (!reversed) { > # Do this if object is smartmatcher... > } > else { > # Do this if object is smartmatchee... > } > }; > > > >> The when construct > >> ================== > >> > >> Form Meaning > >> ================== ================================== > >> when (EXPR) {...} if ($_ ~~ (EXPR)) {...; break} > >> when {BLOCK} {...} if ($_ ~~ sub{BLOCK}) {...; break} > > > > I do wonder if `when {...}` could (internally) be an `if (do {...})` > > instead of `if ($_ ~~ sub { ... })` for performance reasons, > > I'd certainly like the better performance too, but I'd *hate* the fact > that it would eliminate the implicit ~~, and hence would by-pass > overloading if $_ contains an object. :-( > > Damian >Thread Previous | Thread Next