Brent 'Dax' Royal-Gordon wrote:

Rod Adams <[EMAIL PROTECTED]> wrote:


       if $x == 3|4|5|6 {...}

would thread over infix:<==> without any funkiness, since we'll assume 
operators are well written, and can take junctions as parameters, same as:

       if is_prime(3|4|5|6) {...}

Would pass the junction to is_prime, to do with as it pleases, including 
throwing an exception. However,

       if is_prime(�3|4|5|6�) {...}

would thread over is_prime, and collate the results outside of call.



So basically you're proposing that, rather than do one implicit loop
that'll probably do what you want, the default should be to do an
unknown number of implicit loops in somebody else's code, and you have
to ask explicitly for the more sensible behavior. Somehow this
doesn't strike me as an improvement.


What I'm asking for is to be in control of how often I get the possible side effects of calling a function. If I make a call to a DBI method to go insert a record, I want exactly 0 (on error) or 1 (on success) records inserted into my database, _unless_ I told it do otherwise. Since a junction is a single item, it should produce a single effect _unless_ I tell it to expand the values and act like several items at once.

Simply put, I want control over my side effects.

As for whether passing the junction as a junction or passing the junction via autothreading should be the default:

Junctions exists. I want to say "stay a junction" or "explode into pieces, go your separate ways, and then come back". In one case I'm doing nothing to the junction, in the other case I'm doing quite a bit. So it makes sense that the latter is something additional to the former.

Taking into account how common that particular action might be, I chose to propose a rather short modification to it, that still clearly said something special was going on here. One could say I'm just extending the hyper operator from "do this operator several times" to "do this expression several times".

"More sensible behavior" is entirely subject to the exact instance at hand. In the case of let's say C< == >, I want to feed it the raw, unexploded junction.
I well written C< == > should be able to apply all kinds of optimizations to the task at hand, and provide much more sensible results.
I expect calls with operators to be considerably more common than function calls w/ junctions.


So if I grant you your default of autothreading, we then get:

   if $x == �3|4|5� {...}

   given $x {
      when �3|4|5� {...}
   }

Which seemed far more suboptimal than the other way around, IMO.

These semantics also give us the ability to easily mix and match what we send 
to a function, so we can say:

if funky_test(all(@A), �any(@B)�) {...}



sub funky_test ( Junction|Any @a, @b ) { ... }


Unless you have a junction, and you wanted it to autothread on the first parameter, rather than be passed in, in order to get some perceived desirable side effect out of funky_test that passing it a Junction would only give a subset of.

Suppose funky_test is a derivative of C< printf >. Only this printf let's you feed it a junction for the format, and it will sort through them and see which one matches best depending on actual number of parameters, parameter types, etc. Ordinarily, this would be fairly cool stuff.
But let's say you instead wanted it to print the same data with all the different formats. With my calling, you could make the distinction rather easily. With yours, you have to set up the looping yourself.


Basically I'm putting all the power of threading into the hands of the caller.



The caller is not in a position to know if the callee is internally
structured in such a way that passing in a raw junction makes sense.


Sure they are. It's called reading the documentation. If it doesn't say it can handle junctions, it probably can't.

The right place to say "I can handle a junction, don't autothread" is
in the callee; that's the behavior @Larry is proposing.



I'm sending the same message. Only my message goes to the programmer, not the runtime.
I'm also making it where the decision to insert autothreading code or not is made at compile time, not runtime.


As for C< .. >, I'd say that it should handle junctions being fed into it by throwing an exception.



Why is this more sensible than returning a list of junctions in list context and a junction of arrayrefs in scalar context? (I believe infix:<..> will return an arrayref in scalar context, though I could be wrong.)

(The array of junctions is negotiable, by the way; whatever it is,
though, it should probably be the same as the default meaning for list
returns from an autothreaded function.)


About the only thing is could return would be a lazy list of junctions. And about the only places C< .. > gets used is inside C< for > and inside array slice indices. Lists of junctions certainly make no sense in a for loop... the loop cannot simultaneously exit and not exit at the same time. Feeding a list of junctions into an array slice index is asking for what? Another list of junctions out? I just don't see either of those making sense. But if you really want it to do that, I can live with it.

-- Rod Adams

Reply via email to