[proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

[proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Soni "They/Them" L.
I'd like to have the ability to convert, say:

switch (op) {
case OP_TAILCALL: {
   ...
   /*fallthrough*/
}
case OP_CALL: {
   ...
   break;
}
}

into:

if op == OP_TAILCALL then
   ...
   -- fallthrough
orif op == OP_CALL then
   ...
end

because it looks nicer this way I guess.

Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Bas Groothedde
I'd like to have the ability to convert, say:

if op == OP_TAILCALL then
  ...
  -- fallthrough
orif op == OP_CALL then
  ...
end

because it looks nicer this way I guess.


I might be a bit confused, but do you mean `elseif`? 

if op == OP_TAILCALL then 
...
elseif op == OP_CALL then 
...
end

~Bas

Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Bas Groothedde
In reply to this post by Soni "They/Them" L.
I'd like to have the ability to convert, say:

switch (op) {
case OP_TAILCALL: {
  ...
  /*fallthrough*/
}
case OP_CALL: {
  ...
  break;
}
}

into:

if op == OP_TAILCALL then
  ...
  -- fallthrough
orif op == OP_CALL then
  ...
end

because it looks nicer this way I guess.


My apologies, I see what you mean now. Basically if op == OP_TAILCALL or op == OP_CALL, but in separate statements. 
In that particular case, I would rather see a switch-case statement in Lua. 
 
~Bas
Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Soni "They/Them" L.


On 2019-12-23 12:47 p.m., Bas Groothedde wrote:

>> I'd like to have the ability to convert, say:
>>
>> switch (op) {
>> case OP_TAILCALL: {
>>   ...
>>   /*fallthrough*/
>> }
>> case OP_CALL: {
>>   ...
>>   break;
>> }
>> }
>>
>> into:
>>
>> if op == OP_TAILCALL then
>>   ...
>>   -- fallthrough
>> orif op == OP_CALL then
>>   ...
>> end
>>
>> because it looks nicer this way I guess.
>
>
> My apologies, I see what you mean now. Basically if op == OP_TAILCALL
> or op == OP_CALL, but in separate statements.
> In that particular case, I would rather see a switch-case statement in
> Lua.
> ~Bas

switch-case is garbage, this is a lot more powerful because the
condition can be arbitrary. jump tables are just an optimization that
doesn't need to rely on switch-case to exist. (in fact oftentimes
switch-case gets "deoptimized" into if-elseif-goto-etc because it runs
faster!)

Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Chris Jones
In reply to this post by Soni "They/Them" L.
I don't think the proposed syntax really fits with what the word "or" means.

On Mon, 23 Dec 2019 at 15:30, Soni "They/Them" L. <[hidden email]> wrote:
I'd like to have the ability to convert, say:

switch (op) {
case OP_TAILCALL: {
   ...
   /*fallthrough*/
}
case OP_CALL: {
   ...
   break;
}
}

into:

if op == OP_TAILCALL then
   ...
   -- fallthrough
orif op == OP_CALL then
   ...
end

because it looks nicer this way I guess.



--
Cheers,

Chris
Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Soni "They/Them" L.


On 2019-12-23 1:38 p.m., Chris Jones wrote:
> I don't think the proposed syntax really fits with what the word "or"
> means.

if x then
   ...
orif y then
   ...
end

is (effectively) equivalent to

if x then
   ...
end
if x or y then
   ...
end

but x only gets evaluated (and typed) once.

every way to describe this feature, you'll end up using "or" or even "or
if" somewhere, be that in code or in english. see also the subject line
of this email.

>
> On Mon, 23 Dec 2019 at 15:30, Soni "They/Them" L. <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     I'd like to have the ability to convert, say:
>
>     switch (op) {
>     case OP_TAILCALL: {
>        ...
>        /*fallthrough*/
>     }
>     case OP_CALL: {
>        ...
>        break;
>     }
>     }
>
>     into:
>
>     if op == OP_TAILCALL then
>        ...
>        -- fallthrough
>     orif op == OP_CALL then
>        ...
>     end
>
>     because it looks nicer this way I guess.
>
>
>
> --
> Cheers,
>
> Chris



Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Philippe Verdy
What he proposes here is a kind of "fallthrough", like for branches of switches without break in C/C++, but here he wants to allow this also for if...end statements. "elseif" implicitly includes an implicit "break" before a new branch, i.e. exclusive conditions; and he wants inclusive conditions (which has very limited uses, just like break-less branches of switches that fall through.
However it has some usage (e.g. when compiling finite states automatas, or for "exit" procedures at end of blocks to perform cleanup of conditionally-allocated resources in backward direction).

Le lun. 23 déc. 2019 à 18:17, Soni "They/Them" L. <[hidden email]> a écrit :


On 2019-12-23 1:38 p.m., Chris Jones wrote:
> I don't think the proposed syntax really fits with what the word "or"
> means.

if x then
   ...
orif y then
   ...
end

is (effectively) equivalent to

if x then
   ...
end
if x or y then
   ...
end

but x only gets evaluated (and typed) once.

every way to describe this feature, you'll end up using "or" or even "or
if" somewhere, be that in code or in english. see also the subject line
of this email.

>
> On Mon, 23 Dec 2019 at 15:30, Soni "They/Them" L. <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     I'd like to have the ability to convert, say:
>
>     switch (op) {
>     case OP_TAILCALL: {
>        ...
>        /*fallthrough*/
>     }
>     case OP_CALL: {
>        ...
>        break;
>     }
>     }
>
>     into:
>
>     if op == OP_TAILCALL then
>        ...
>        -- fallthrough
>     orif op == OP_CALL then
>        ...
>     end
>
>     because it looks nicer this way I guess.
>
>
>
> --
> Cheers,
>
> Chris



Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Egor Skriptunoff-2
In reply to this post by Soni "They/Them" L.
On Mon, Dec 23, 2019 at 5:30 PM Soni "They/Them" L. wrote:
if op == OP_TAILCALL then
   ...
   -- fallthrough
orif op == OP_CALL then
   ...
end

because it looks nicer this way I guess.



The meaning of "orif" keyword is not intuitive-clear to a reader.
I would prefer to use explicit "goto" in case I need to implement fallthrough.
Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Soni "They/Them" L.


On 2019-12-23 4:42 p.m., Egor Skriptunoff wrote:

> On Mon, Dec 23, 2019 at 5:30 PM Soni "They/Them" L. wrote:
>
>     if op == OP_TAILCALL then
>        ...
>        -- fallthrough
>     orif op == OP_CALL then
>        ...
>     end
>
>     because it looks nicer this way I guess.
>
>
>
> The meaning of "orif" keyword is not intuitive-clear to a reader.
> I would prefer to use explicit "goto" in case I need to implement
> fallthrough.


it's definitely more intuitive than switch-case fallthrough by a long shot.

Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Philippe Verdy
In reply to this post by Egor Skriptunoff-2
if op == OP_TAILCALL then
   ...
   goto fallsto_call;
elseif op == OP_CALL then
  fallsto_call:
   ...
end

Yes it's better (the compiler will manage itself to reorganize the jumps to implement fallsthrough it it wishes, depending on how it compiles the conditional jumps for if/elseif-tests which may contain "and/or" expressions that also frequently generate branches if there's no simple bitmasking expressions to reduce them without branches), just like it can swap branches if it helps it to use short relative jumps in less instructions, depending also on branch prediction (if the compiler has profiling data).

But for the source language, I still think that a switch is still simpler to read, even with a "fallthrough" comment (or directive for linters).

switch (op)
case OP_TAILCALL:
   ...
   // fallthru
case OP_CALL:
   ...
  break
end

And if we have a switch without break (all branches are breaking implicity, then yes we need a goto or a fallthru statement (not just a directive for linters or comment for programmers). Most programmers are aware of the syntax of switches, and they are usually cleander, faster to type; the only caveat is that fallthrough are traps which do not allow easy refactoring (e.g. adding cases, commenting out some of them: so an explicit fallthru statement is certainly better if it is labelled.

Le lun. 23 déc. 2019 à 20:51, Egor Skriptunoff <[hidden email]> a écrit :
On Mon, Dec 23, 2019 at 5:30 PM Soni "They/Them" L. wrote:
if op == OP_TAILCALL then
   ...
   -- fallthrough
orif op == OP_CALL then
   ...
end

because it looks nicer this way I guess.



The meaning of "orif" keyword is not intuitive-clear to a reader.
I would prefer to use explicit "goto" in case I need to implement fallthrough.
Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Philippe Verdy
In reply to this post by Soni "They/Them" L.
"Intuitive" is not enough: the order of evaluation of conditions matters (the fact they are not mutually exclusive and create complex conditions that are split and spread across large spans of code, can be challenging for refactoring. For this reason if the switch branches are complex (and cannot just call a single function or perform a single assignment but contain structured statements or many assignments and calls, it's safer for refatoring to first evaluate the conditions and use goto's with clear labels, then develop each label.

There are caveats however due to local variable scopes when they are declared or initialized in specific subbranches. There's no general "good" solution that matches all needs.

For finite state automatas, it's generally better to use many gotos and group the code for testing all conditions tests together before the code for all conditional branches. Switch'es are good by the fact that the conditions they test is simple and don't require declaring unique labels: they are then more compact, and easier to maintain. I do like switch'es.

I don't care at all if they are finally compiled as computed gotos (indirection via an array of label pointers), or series of if-tests and many jumps (the same also applies to if/elseif/else/end blocks that can compile using all the same options):

This is a compiler implementation detail anyway. For programmers in alny language, it has to be concise, clean, easy to read and manage for refactoring. Lua can perfectly be built for the programmer's ease of understanding, any compiler will be able to find all the possible tricks itself.


Le lun. 23 déc. 2019 à 22:00, Soni "They/Them" L. <[hidden email]> a écrit :


On 2019-12-23 4:42 p.m., Egor Skriptunoff wrote:
> On Mon, Dec 23, 2019 at 5:30 PM Soni "They/Them" L. wrote:
>
>     if op == OP_TAILCALL then
>        ...
>        -- fallthrough
>     orif op == OP_CALL then
>        ...
>     end
>
>     because it looks nicer this way I guess.
>
>
>
> The meaning of "orif" keyword is not intuitive-clear to a reader.
> I would prefer to use explicit "goto" in case I need to implement
> fallthrough.


it's definitely more intuitive than switch-case fallthrough by a long shot.

Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Stefan-2
In reply to this post by Philippe Verdy
Is that even possible?

Am 23.12.2019 um 22:00 schrieb Philippe Verdy:
 > if op == OP_TAILCALL then
 >     ...
 >     goto fallsto_call;
 > elseif op == OP_CALL then
 > fallsto_call:
 >     ...
 > end
 >

This gives me "no visible label 'fallsto_call' for <goto>"

Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Egor Skriptunoff-2
On Tue, Dec 24, 2019 at 2:54 AM Stefan wrote:
Is that even possible?
This gives me "no visible label 'fallsto_call' for <goto>"


Ops!  Indeed.
Reply | Threaded
Open this post in threaded view
|

Re: [proposal] "or if" - run this next block if the previous one ran *or if* the condition is true

Philippe Verdy
In reply to this post by Stefan-2
That was replied in a following message. Yes this is limitating, and for now the only workaround is to use a boolean flag variable to track conditions, and to retest that variable in subsequent ifs to do common actions:

> var do_call = false;
> if op == OP_TAILCALL then
>     ...
>      do_call = true;
> elseif op == OP_CALL then
>      do_call = true;
> end
> if do_call then
> ...
> end

There's no such problem in C/C++, even if you jump to the scope of a local variable (which may then turn unitialized; C/C++ preallocates all local variables at the same time at the function entry scope without initializing them, or some security-enhanced C/C++ compiler zero them all before actual initialization; but within the same function, random gotos may leave their value at their previous value without properly reinitilizing them where they are declared but in a statement avoided by the direct goto's. This is sometimes used however to create optimized parsers/scanners and finite state automatas, but programmers have to follow the logic of varaible states more scrupulously.

Tracking the variable scopes inside a function that allows breaks, random gotos, or exception catching is tricky for compilers, espêcially in C++ with accessors, implicit constructors. In Lua this is simpler to track, but the syntax has its limitations.

The general solution using explicit boolean flag variables however is warrantied to work, even if it has a small performance penalty, not a problem with programs running in modern PCs, but may be a problem for small devices with limited memory (small stacks), few registers, and limited code sizes, running at low frequency: adding extra variables adds a cost.

However even the smallest devices today have CPUs that run near the Gigahertz range and embed a reasonnable local memory cache in their chip. Compilers (that should do their work on a decent machine) can still find tricks to track all varaible usages and value domains. Unfortunately, the Lua language has a dynamic type system (at the public programming API), and so compilers have to generate an alternate typing system (this is done already in Javascript, basically the dynamic datatypes are converted using interface signatures built by the compiler, and at run time the interfaces become static classes that can be optimized according to each value domain, so that the compiler can determine when it really needs to assign varaibles with complete values, or just use the few bits that are needed for correct execution. Local flag variables will then have little or no cost, and may even be left completely unallocated when their only use is to determine NOT a data flow but a code flow with conditional jumps (unconditional jumps will be dropped as much as possible by the compiler which will then attempt to implement the "fallthru" strategy itself

----

Compilers (as well CPUs in their internal scheduler from ISA to micro-ops in their multiple pipelined threads) make lot of efforts to determine data dependency. What was costly in old generations of CPUs is less important today (except where it can impact security, notably for branch prediction and speculative execution due to possible time-based attacks: this has seriously complicated the design of new processors as it becomes much arder for them to track the dataflow, and some new instructions like "barriers" are being added and must be used with by compilers to avoid these issues, with some performance costs: data flow and code flows are no longer considered fully independant and it is extremekly complex to track them in modern CPUs that have many parallel flows, schedulers, dynamic register stacks and multiple layers or caches and complex management of internal clocks and internal buses with variable frequency rates, plus now recovery procedures for random conditions; this wil lbecome even harder in the future when processors will start using very fast but probabilistic algorithms instead of imperative instructions, as we have reached now the physical limits where exact binary processing is possible; tomorrow processors will work with possible "errors" and will include many statistic and predictive behavior with delayed corrections, and the possibility to continue working even if some parts of the chip are wearing or overheating: data will constantly and dynamically be reflowed; step by step executiion, driven by clocks will no longer be the only solution, and single data paths will be harder to isolate from each other but will have to manage mutual side-effects).

For now, there's not a single programming language (not even Lua which is still based on the Turing machine model) that is really ready and enough theorized to work with future processors. And binary processing using bits is not near from the end for faster processing. We'll start using probabilistic qbits, and we already have processings (for networking) that use more complex coding (see for example DSL and 5G codecs, as well as audio/video encoding, or "machine learning" algorithms). for newer architectures, impertive binary processing with exact clocks, barriers, isolated buses, imperative errors or exception handling will be insufficient, and softwares will need a language that allows backtracking and feedbacks for correction until a stability condition is reached. Microbecnchmarking will then become non-sense, when the goal will just be to get more global performance. Algorithms will need to be self-adaptative (it won'ty then matter if internal microstates are wrong when the expected response is more global.

Some interesting results are however being observed today with "machine learning" and "big data", but as well in 3D video acceleration for gaming, and large-scale simulations (fluid dynamics, meteorology, behavior analysis, fundamental physics...). The algorithm they use are no longer based on discrete variables, but use large matrixes of statistics that are "computed" with massive parallelism allowing "errors" or instability at the internal microlevels, and strict data locality is simply removed, allowing also interesting features like scalability, resilience and recovery for temporary or permanent "defects". Even the "defects" contain interesting data that can be used. Newer algorithms will use better strategy than basic artihmetic, they will work with other numeric models, with things like fourier transforms, stochastic equations, statistic sampling and evaluators, data feedback, error corrections, resonance attenuation for maintaining stabiility and reliability. These algotithms will work not just on bits but on fractions of bits, and we'll even see non numeric solution using analog processing for even better precision. Binary clocks will also be eliminated in many parts (they are the major cause of heat dissipation at high frequency rates above 1GHz and cause faster wearing of components in chips).

Le mar. 24 déc. 2019 à 00:54, Stefan <[hidden email]> a écrit :
Is that even possible?

Am 23.12.2019 um 22:00 schrieb Philippe Verdy:
 > if op == OP_TAILCALL then
 >     ...
 >     goto fallsto_call;
 > elseif op == OP_CALL then
 > fallsto_call:
 >     ...
 > end
 >

This gives me "no visible label 'fallsto_call' for <goto>"