Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
PallHaraldsson opened this issue Jan 8, 2017 · 11 comments
Labels
breaking This change will break code speculative Whether the change will be implemented is speculative

Comments

@PallHaraldsson
Copy link
Contributor

PallHaraldsson commented Jan 8, 2017

What @Ismael-VC wants with #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:

  • Disallow calling functions with side-effects (braking change for && and || but not new operators).
  • Ignoring side-effects!

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.

  • I'm unclear on:

`(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
Copy link
Member

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
Copy link
Contributor

Ismael-VC commented Jan 8, 2017

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

In Julia is roughly the same as:

  • get!(prec_table, :in, get(prec_table, :(==), 0))

I think.

@TotalVerb
Copy link
Contributor

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

@yuyichao yuyichao added breaking This change will break code speculative Whether the change will be implemented is speculative labels Jan 8, 2017
@PallHaraldsson
Copy link
Contributor Author

PallHaraldsson commented Jan 9, 2017

@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
Copy link
Member

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
Copy link
Contributor

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

@PallHaraldsson
Copy link
Contributor Author

PallHaraldsson commented Jan 9, 2017

"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
Copy link
Contributor

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
Copy link
Member

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
Copy link
Member

[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
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking This change will break code speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

6 participants