aseba-community / aseba

Aseba is a set of tools which allow beginners to program robots easily and efficiently. To contact us, please open an issue.
http://aseba.wikidot.com
GNU Lesser General Public License v3.0
48 stars 62 forks source link

partial lazy evaluation (conjunctions, disjunctions) #301

Open witwicki opened 10 years ago

witwicki commented 10 years ago

This is not a critical issue, but rather something aseba is lacking that I seem to take for granted when coding in other high-level languages...

In evaluating a conjuction of logical expressions, aseba evaluates all expressions even if the first one is false.

Example:

var a[3]
var i = 0
while (i<3 and a[i]==0) do
   i = i + 1
end

I would expect this loop to terminate with i set to 3, but instead it dies because "a[i]==0" still gets evaluated even after i<3 becomes false.

Of course, there are simple workarounds. But this was still a nuisance when I encountered it because I did not expect aseba to behave as such.

vaussard commented 10 years ago

So, looking at the simple case

if a == 0 and b == 0 then
    ...
end

I can see that the generated bytecode is like:

test a == 0
test b == 0
goto end if both false 
...
end:

So this is a problem due to Aseba having a custom bytecode to evaluate two conditions at the same time. The side effect is that both conditions must be evaluated before the branch.

On the compiler side, I could implement a workaround to generate the following bytecode:

test a == 0
goto end if false
test b == 0
goto end if false
...
end:

The obvious downturn is an increased bytecode size, and a slower execution (two conditional tests, instead of one).

So before doing this, we should discuss if this is a reasonable approach. Of course, the same applies for 'or' conditions.

stephanemagnenat commented 10 years ago

I agree with your analysis. The bytecode is not very suited for lazy evaluation. I would say that it is not a priority to implement it for now, but I am open for discussion.

ypiguet-epfl commented 6 years ago

I disagree with your analysis. With your example, my disassembler gives this for the compiled code (tested in 1.6):

    7  3000       load a
    8  1000       push.s 0
    9  800a       eq
   10  3001       load b
   11  1000       push.s 0
   12  800a       eq
   13  a011 xxxx  jump if not and @end
...
@end:

It would be the same size, and one instruction less, with lazy evaluation:

    7  3000       load a
    8  1000       push.s 0
    9  a00a xxxx  jump if not eq @end
   11  3001       load b
   12  1000       push.s 0
   13  a00a xxxx  jump if not eq @end
...
@end:

For the execution speed, lazy evaluation is beneficial most of the time, even in cases it isn't required. In a VM like Aseba's, it's certainly irrelevant.