JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.57k stars 5.47k forks source link

Reserve/add `and` and `or` with relaxed semantics from [left] only short-circuiting, e.g. allowing & or | #19933

Open PallHaraldsson opened 7 years ago

PallHaraldsson commented 7 years ago

What @Ismael-VC wants with https://github.com/JuliaLang/julia/pull/19788 are strict aliases. There are other options, the problem may not be with his code though.*

If taken at face-value, left short-circuiting disallows running first the (or only) right-side:

if slow_function!(x) && fast_function!(y)
  takes_a_long_time_getting_here
else
  or_takes_a_long_time_getting_here
end

I have some ideas to fix that, they may be strictly implementations details, NOT incompatible with left short-circuiting, but then you need lots of prove-work to show absence of "side-effects".

There are two options:

if fun1!(x) and fun2!(x) # note x-es are repeated, not y as above

is even worse [maybe the other if can work despite the !s ]

If we announce and and or not promising too much, maybe reusing his code (mostly; changes would be elsewhere, and in NEWS.md), then his code could possibly work.

I want to allow running, either side, or both (as &), or even neither (yes, that's a possibility..). And running both sides at once in separate thread, possibly killing them half-way through.

`(define is-prec-comparison? (augment-prec-with-infix prec-comparison 'in 'isa))

[..]

(put! prec-table 'in (get prec-table '== 0)) ; add in to the prec-table (put! prec-table 'isa (get prec-table '== 0)) ; add isa to the prec-table`

JeffBezanson commented 7 years ago

I would guess that in practice there is not much useful parallelism to be had from the evaluation semantics of &&. It certainly doesn't need to be the default. I think that could be handled well by an @and macro, or a Parallel.and function. Incidentally, this is an example of a case where it's useful for and to be available to libraries.

Ismael-VC commented 7 years ago

(put! prec-table 'in (get prec-table '== 0))

In Julia is roughly the same as:

I think.

TotalVerb commented 7 years ago

Note that the PR is somewhat stale and now the hacks used in that PR are no longer necessary.

PallHaraldsson commented 7 years ago

@yuyichao the braking label isn't needed, as I do not want to change && and || (at least not yet..).

@JeffBezanson "I would guess that in practice there is not much useful parallelism to be had from the evaluation semantics of &&."

[I'm not saying you're asking for parallel, just not disallowing.]

If I recall, on average every third assembly instruction is a conditional. In leaf functions, my semantics do not help (while the semantics do not rule out running serially, doing same as && or || (or even & or |)).

For non-leaf-functions and/or comparison chaining, my semantics are even better, e.g.:

if a(x) < b(y) < c(x) .. # implicitly a(x) < b(y) && b(y) < c(x) ..

through DeMorgan's law I can have a chain of ||s (and simplyfying, assuming b(y) is actually a constant):

if !(!(a(x) < b) || !(!(b < c(x)) || ..

if the chain is long enough, here only two functions, more is even better, but two will do.

I can run a and c (and all the other functions, if more) concurrently, with a race to the finish line, and kill the other one[s], when truth value of either is known.

JeffBezanson commented 7 years ago

If I recall, on average every third assembly instruction is a conditional

Yes, for instruction-level parallelism you just want non-short-circuiting &. Where we can prove expressions pure, we could already convert && to & without changing its semantics; LLVM probably does this in some cases (at this time, probably only very simple ones).

If you're talking about threads, my point remains. Sure parallel and is useful, I just don't think it needs special syntax.

TotalVerb commented 7 years ago

Also, this functionality, if necessary, can be provided more easily, more clearly, and to a much better standard of quality by a macro.

PallHaraldsson commented 7 years ago

"Sure parallel and is useful, I just don't think it needs special syntax"

If you mean nothing more, you might be right, I'm exploring that.. (maybe optimizations do not need allowance) but if you mean:

"this functionality, if necessary, can be provided more easily, more clearly, and to a much better standard of quality by a macro."

then you're talking about hand-tuning, and keep in mind that Julia is made for scientists not computer scientists, who may not like manual as much as automatic.

You can compare this to rule based optimizers for SQL vs. cost-based that won out.

If you do want to hand tune join order, or in this case evaluation by using e.g. the standard && (intermixed with and), that keeps it semantics.

"LLVM probably does this in some cases" in the simple case I had (the uppercase function), it didn't change to & and I did it manually, see thread on discourse. https://discourse.julialang.org/t/why-is-x-or-a-function-call-so-long-slow-not-inlined/1264/21?u=palli

TotalVerb commented 7 years ago

No, I am not talking about hand tuning. I am just saying that whatever parallel semantics you like, including this automatic optimization, can and should be achieved with a macro.

JeffBezanson commented 7 years ago

You can compare this to rule based optimizers for SQL vs. cost-based that won out.

And how have auto-parallelizing compilers fared? Obviously I'm all in favor of compiler optimizations, but experiments with evaluation rules that allow parallelism (e.g. in evaluating function arguments) have not brought significant real-world parallel speedups. What seems to work are (1) parallelized libraries (where the parallelism is fully automatic from the user's perspective) and (2) occasional parallel loops and maybe a few spawns.

StefanKarpinski commented 7 years ago

[I would also add: (3) full composability of (1) and (2) so that many layers of exposed potential parallelism do not conflict with each other.]

PallHaraldsson commented 7 years ago

Note I'm only advocated parallel as one option with: e.g. "And running both sides at once in separate thread, possibly killing them half-way through."

Allowing e.g. serial evaluation order from right-to-left as would have been helpful, as with here:

https://discourse.julialang.org/t/left-to-right-strict-comparison-chaining-order-considered-harmful-by-me/1420

It surpriced me that mandated short-circuit isn't actually synonym for comparision chaining. But implemented as such - currently.

Yes, more than one allowed way means non-determinisim.. as there. Unless you prove there are no side-effects. Thus possibly disallowing !-functions.