Re: The .trans method and Least Surprise

2012-07-20 Thread Carl Mäsak
yary ():
 Speaking as a non-p6-coder proposal sounds good to me though the
 spec raises some other questions.

The tr/// quote-like operator now also has a method form called
 trans(). Its argument is a list of pairs. You can use anything
 that produces a pair list:

 $str.trans( %mapping.pairs );

 Does Perl 6 guarantee the order in which pairs are returned from a
 hash? If not, then the following code won't always return the same
 thing:

 my %mapping = 'a' = 'x', 'x' = 'b'; say 'ax'.trans(%mapping);

Perl 6 does not guarantee any particular order in which pairs are
returned from a hash. However, this is a non-issue with .trans, since
.trans doesn't care about the order.

Not sure how clear it is from the spec, but .trans traverses things in
*one* pass. That's the idea of it. So there's no conflict in the above
example. 'a' goes to 'x' and 'x' goes to 'b', regardless of pair
ordering.

See 
http://perl6advent.wordpress.com/2010/12/21/day-21-transliteration-and-beyond/
for deeper delvings into this.

Even if I didn't see reasons why .trans shouldn't care about hash key
ordering on the grounds of what it is in Perl 6, I would still be
against it on the grounds of it being based on tr/// in Perl 5, which
is on-pass and doesn't care about the ordering of characters on the
left.

 It might say 'bb' or 'xb', depending on how the pairs are returned.
 That might be considered a programmer's error, but it seems
 less-than-optimal that these two lines have the same result in my
 somewhat dated Rakudo install:

 say 'ax'.trans(a = x, x = b)
 xb
 say 'ax'.trans(x = b, a = x)
 xb

 - even if it is completely in accord with spec.

No. As above.

Perl 5 agrees:

$ perl -wle '$_ = ax; tr/ax/xb/; print'
xb
$ perl -wle '$_ = ax; tr/xa/bx/; print'
xb

 And since mapping is a hash, it prevents a series of transl{ations
 iterations} with the same from in a single call.

And that's a feature.

If you want a series of translations, make a series of .trans calls.
(Unless my proposal goes through, in which case you should make a
series of .translate calls.)

// Carl


The .trans method and Least Surprise

2012-07-13 Thread Carl Mäsak
Something's bothering me about the .trans method. This email lists a
proposal to split its semantics into two methods.

I'm not yet convinced myself about this proposal. It's quite late in
the game to make spec changes of established methods, and the change
will break some downstream application code, some of which I wrote. So
if the advantages don't come shining through, I will withdraw my
proposal. But I thought I would make a case for it and see what people
think of it.

Here's the .trans spec:

 http://perlcabal.org/syn/S05.html#Transliteration

Summary of the spec: .trans does what tr/// does (in Perl 5, and Perl
6). .trans also does a bunch of cool stuff with strings and regexes
and Longest-Token Matching that tr/// never did.

My proposal is to split away the cool stuff with strings and regexes
and LTM into its own method.

For purposes of concreteness, I will call this proposed method
.translate -- name proposals are allowed in the thread and on the
#perl6 channel, but in order to reduce bikeshedding, proposals without
a rationale will be ignored. Also note that the discussion is not
primarily about the name, but about the split itself.

Here are my reasons for the split:

* The spec literally goes from saying that the tr/// operator has a
method form, to overloading this method form with features that are
not in tr///. The method is showing signs of lack of cohesion.

* I use the more advanced features frequently, and they're great for
parallel, one-pass substitution of substrings. They're an improvement
over Perl 5's corresponding features. I don't want them to go away,
just to separate them into their own method.

* Linguistically, trans*literation* (which is what Ctr stands for)
is about replacing individual characters. Substituting bigger chunks
is a kind of translation.

* Over the years, I've seen people struggling with the API of .trans,
which is for all intents and purposes two separate APIs: one involving
pairs of strings, and one involving pairs of Positional (spec says
Array). Something about the whole thing violates Least Surprise. This
whole email was prompted by my having to check the spec for the
umpteenth time and realizing that the API simply doesn't vibe with me.
Splitting up the two separate APIs into two methods would help.

* The more advanced parts of the current API -- the ones that allow
the right hand sides of pairs to be regexes or closures -- could be
migrated out along with the pairs-of-Positional API. Then the .trans
method would be left to handle *only* the things that tr/// handles,
and the .translate method could do the cool stuff.

* .trans could then have specially optimized code which does one-char
substitution efficiently. Though we're not there yet, because of the
cool stuff that I propose to move out into .translate, the plans for
an efficient implementation of .trans involve somehow generating a
grammar on-the-fly and then running it on the string to be
substituted. This seems like extreme overkill for tr///.

Have these things been bothering any of you too? Does the split make
sense? Would it help us to simplify the API and make people Less
Surprised by it? Are the projected wins of the spec change worth the
upsetting of the ecosystem?

Hopefully,
// Carl


Re: The .trans method and Least Surprise

2012-07-13 Thread yary
Speaking as a non-p6-coder proposal sounds good to me though the
spec raises some other questions.

The tr/// quote-like operator now also has a method form called
 trans(). Its argument is a list of pairs. You can use anything
 that produces a pair list:

 $str.trans( %mapping.pairs );

Does Perl 6 guarantee the order in which pairs are returned from a
hash? If not, then the following code won't always return the same
thing:

my %mapping = 'a' = 'x', 'x' = 'b'; say 'ax'.trans(%mapping);

It might say 'bb' or 'xb', depending on how the pairs are returned.
That might be considered a programmer's error, but it seems
less-than-optimal that these two lines have the same result in my
somewhat dated Rakudo install:

 say 'ax'.trans(a = x, x = b)
xb
 say 'ax'.trans(x = b, a = x)
xb

- even if it is completely in accord with spec.

And since mapping is a hash, it prevents a series of transl{ations
iterations} with the same from in a single call.
trans('A..J'='0..9', 'a..z'='A..Z', 'A..J'='zyxjihcba');
- which is a contrived example that could be rewritten to avoid the
clash, but it shows the idea.

So if you're going to alter the spec, I suggest changing the method
from accepting a hash of pairs, to accepting an array of pairs.

I still really like the idea of passing 'from' = 'to' as a pair, and
think even 'subst' should accept a pair because it looks good in the
source!