1. Major Bug in Interpreter [Attn: Robert Craig]

Hello All,

I just wanted report this bug before 2.5 went Final, cause this is indeed
a major bug.  I've tested this under 2.5 and 2.4, and 2.4 works correctly,
but 2.5 does not.  You can see it happening when you invoke the trace
like I have it written.

with trace
sequence stack

constant NewValue = {0,0,1,0}
stack = {}

trace(1)
function recursive_call(integer i)
	integer ib
	stack &= 0
	ib = length(stack)
	stack[ib] = NewValue
	for x = 1 to 4 do
		if stack[ib][i] = 0 then
			stack[ib][i] = recursive_call(i+1)
		end if
	end for
	return ib
end function

integer i
i = recursive_call(1)
? stack
machine_proc(26,0)


It should be pretty self explainitory, but incase your wondering, stack
is a top-level variable, not a temporary variable.  when running through
recursion calls, the last sequence to be added to the list, get's free'd,
voided, or whatever, then it drops off the sequence list after the recursion
call is completed.  This shouldn't be happening, cause... again, stack is
a top-level variable.

I have confirmed that 2.5 Beta is the one I'm using when this happens, if
anyone else wants to test, feel free to.

The way the sequence SHOULD look after the exit of all recursion calls:
stack = { {2,0,1,0}, {0,3,1,0}, {0,0,1,0} }

The way the sequence DOES look with 2.5 Beta:
stack = { {2,0,1,0} }

new topic     » topic index » view message » categorize

2. Re: Major Bug in Interpreter [Attn: Robert Craig]

Mario Steele wrote:
> I just wanted report this bug before 2.5 went Final, cause this is indeed
> a major bug.  I've tested this under 2.5 and 2.4, and 2.4 works correctly,
> but 2.5 does not.  You can see it happening when you invoke the trace
> like I have it written.
> 
> }}}
<eucode>
> with trace
> sequence stack
> 
> constant NewValue = {0,0,1,0}
> stack = {}
> 
> trace(1)
> function recursive_call(integer i)
> 	integer ib
> 	stack &= 0
> 	ib = length(stack)
> 	stack[ib] = NewValue
> 	for x = 1 to 4 do
> 		if stack[ib][i] = 0 then
> 			stack[ib][i] = recursive_call(i+1)
> 		end if
> 	end for
> 	return ib
> end function
> 
> integer i
> i = recursive_call(1)
> ? stack
> machine_proc(26,0)
> </eucode>
{{{


It's not a bug.
It's a change in the way things work in a rare,
ambiguous, and undocumented area.

I should mention this in the 2.5 alpha release notes
or somewhere.

In order to efficiently support the new $ feature,
I had to change the order of operations when subscripts
are performed on the left-hand-side of an assignment. e.g.

stack[ib][i] = recursive_call(i+1)

In 2.4, all expressions are evaluated first, then
the lhs subscripting is performed and the rhs value is assigned.

In 2.5, I (generally) need to perform each lhs subscript as I go along,
from left to right, before evaluating the subscript expression
that comes after it, since I may need to know the proper value of $
in the subsequent subscript expression.

In 2.4, you obviously counted on recursive_call() being completed
before the subscripted assignment was done, and you counted
on stack being changed by the side-effects of that call, before
the assignment to stack was done.
None of this was documented in the Reference Manual. 
You just tried it, and it worked.

In 2.5, the lhs var being subscripted will keep its original
value (I just increment its ref count), and will then be 
modified by the assignment. The effect of any side-effects 
on that var (i.e. stack) will be lost
as the assignment is completed. If I don't preserve the original
value, I can easily have crashes due to your having 
"pulled the rug out from under me" while I'm in the middle of
trying to subscript a now non-existent value. And, no, I don't
want to insert checks all over the place for this bizarre situation.

You only have to worry about this change if you are doing 
a subscripted assignment with multiple subscripts on the lhs,
and in the same statement you are calling a function 
that has the side-effect of modifying the lhs var (even as it
is being assigned-to).

You can make things work the way you want, and also
make your code more readable, by performing the function call 
in a separate statement before trying to modify the lhs variable.

Regards,
   Rob Craig
   Rapid Deployment Software
   http://www.RapidEuphoria.com

new topic     » goto parent     » topic index » view message » categorize

3. Re: Major Bug in Interpreter [Attn: Robert Craig]

Robert Craig wrote:
> It's not a bug.
> It's a change in the way things work in a rare,
> ambiguous, and undocumented area.
> 
> I should mention this in the 2.5 alpha release notes
> or somewhere.
> 
> In order to efficiently support the new $ feature,
> I had to change the order of operations when subscripts
> are performed on the left-hand-side of an assignment. e.g.
> 
> stack[ib][i] = recursive_call(i+1)
> 
> In 2.4, all expressions are evaluated first, then
> the lhs subscripting is performed and the rhs value is assigned.
> 
> In 2.5, I (generally) need to perform each lhs subscript as I go along,
> from left to right, before evaluating the subscript expression
> that comes after it, since I may need to know the proper value of $
> in the subsequent subscript expression.
> 
> In 2.4, you obviously counted on recursive_call() being completed
> before the subscripted assignment was done, and you counted
> on stack being changed by the side-effects of that call, before
> the assignment to stack was done.
> None of this was documented in the Reference Manual. 
> You just tried it, and it worked.
> 
> In 2.5, the lhs var being subscripted will keep its original
> value (I just increment its ref count), and will then be 
> modified by the assignment. The effect of any side-effects 
> on that var (i.e. stack) will be lost
> as the assignment is completed. If I don't preserve the original
> value, I can easily have crashes due to your having 
> "pulled the rug out from under me" while I'm in the middle of
> trying to subscript a now non-existent value. And, no, I don't
> want to insert checks all over the place for this bizarre situation.
> 
> You only have to worry about this change if you are doing 
> a subscripted assignment with multiple subscripts on the lhs,
> and in the same statement you are calling a function 
> that has the side-effect of modifying the lhs var (even as it
> is being assigned-to).
> 
> You can make things work the way you want, and also
> make your code more readable, by performing the function call 
> in a separate statement before trying to modify the lhs variable.


Okay, all of this I can understand.  However, this now just added a new
level of complexity to my code for a OOP library I'm currently developing.

The reason why I brought this up, is cause I'm using a similar routine to
create Nested Objects based apon a decloration of a class.

EG:
Class("MyClassB")
    Member("MyVar1",INTEGER)
EndClass()

Class("MyClassA")
    Member("MyVar2",ATOM)
    Member("ClassB","MyClassB")
EndClass()

constant NewClass = new("MyClassA",{})


Since the new design of Euphoria, makes it impossible for me to correctly
do recursive creation of Sub-Classes, I now have to find a way to create
the sub-class effectivly, cause it seems to me, that anyway I go, according
to the new rules, as soon as I exit a call, the sequence I just added to
the variable, Now dis-appears on me.

About the only way I can make this work, is if I have some kind of construct
routine to create all the nested sequences, and when they are all created,
return it to the caller, and have the caller store the entire sequence into
the variable, in order for the changes to remain constant.

This equals more instructions for the interpreter to execute, and parse,
which will equal slower speeds.  Not that I was developing this library for
speed.

Oh well, Back to the drawing board.  Maybe I'll come up with something to
make the changes STAY in the variable.

Mario Steele

new topic     » goto parent     » topic index » view message » categorize

4. Re: Major Bug in Interpreter [Attn: Robert Craig]

Okay, after doing some experimenting, I found what you mean.

You should word the Documentation, and explination more vividly, then what
was originally stated:

In order to recursivly assign something to a sequence, you need to
in-directly assign the value after the recursive call is made.

Example:
function recursive_call(integer i)
    integer ib, id
    stack &= 0
    ib = length(stack)
    for x = 1 to 4 do
        if stack[ib][i] = 0 then
            id = recursive_call(i+1)
            stack[ib][i] = id
        end if
    end for
    return ib
end function


Which to me, that's a waste of a variable space, that Euphoria is now forced
to have to allocate, and deallocate everytime the function is ran through.

But anyways, I got it figured out now.  It lends nothing to readability,
just confusion, and making recursive calls to modify sequences utterly
useless.

Mario Steele

new topic     » goto parent     » topic index » view message » categorize

5. Re: Major Bug in Interpreter [Attn: Robert Craig]

On Sun, 13 Feb 2005 11:49:30 -0800, Mario Steele
<guest at RapidEuphoria.com> wrote:

>Oh well, Back to the drawing board.  Maybe I'll come up with something to
>make the changes STAY in the variable.

What Rob actually said was you have to do this:

			tmp = recursive_call(i+1)
			stack[ib][i] = tmp

Regards,
Pete

new topic     » goto parent     » topic index » view message » categorize

6. Re: Major Bug in Interpreter [Attn: Robert Craig]

Mario Steele wrote:
> 
> Hello All,
> 
> I just wanted report this bug before 2.5 went Final, cause this is indeed
> a major bug.  I've tested this under 2.5 and 2.4, and 2.4 works correctly,
> but 2.5 does not.  You can see it happening when you invoke the trace
> like I have it written.
> 
> }}}
<eucode>
> with trace
> sequence stack
> 
> constant NewValue = {0,0,1,0}
> stack = {}
> 
> trace(1)
> function recursive_call(integer i)
> 	integer ib
> 	stack &= 0
> 	ib = length(stack)
> 	stack[ib] = NewValue
> 	for x = 1 to 4 do
> 		if stack[ib][i] = 0 then
> 			stack[ib][i] = recursive_call(i+1)
> 		end if
> 	end for
> 	return ib
> end function
> 
> integer i
> i = recursive_call(1)
> ? stack
> machine_proc(26,0)
> </eucode>
{{{

> 
> It should be pretty self explainitory, but incase your wondering, stack
> is a top-level variable, not a temporary variable.  when running through
> recursion calls, the last sequence to be added to the list, get's free'd,
> voided, or whatever, then it drops off the sequence list after the recursion
> call is completed.  This shouldn't be happening, cause... again, stack is
> a top-level variable.
> 
> I have confirmed that 2.5 Beta is the one I'm using when this happens, if
> anyone else wants to test, feel free to.
> 
> The way the sequence SHOULD look after the exit of all recursion calls:
> stack = { {2,0,1,0}, {0,3,1,0}, {0,0,1,0} }
> 
> The way the sequence DOES look with 2.5 Beta:
> stack = { {2,0,1,0} }

Technically speaking its not a bug, in the sense that it is not
failing to meet specifications.

I will defend Robert's right to implement Euphoria with this behaviour, 
namely that from v2.5, Euphoria evaluates the left hand side (LHS) of
an assignment before it evaluates the RHS. Even though no major language
does this (they evaluate the RHS first then the LHS), Robert
has the right to have Euphoria do what he likes. The reasons for
him doing this aren't even relevant, because regardless of why he has
choosen to change the behaviour of Euphoria, he has every right to do it.

If any mistakes have been made, it could be that RDS has not documented
this behaviour (i.e. specified it), and that RDS has not explicitly 
brought to our attention this change in behaviour. These are oversights
that I'm positive will be rectified before the final release.

It is not unreasonable for people to assume that RHS-before-LHS evaluation
would be done, as this is the normal or common approach used in major
languages such as C, C++, C#, Java, VB, COBOL, Pascal, Fortran, etc...
It just needs to be clearly documented, with examples of how to make it
work like we all expect, for us to move forward.

I think we all agree that Euphoria is not a conventional language, in that
it does do a few things that other languages do not do. For example
the notable "if seq = seq then ..." syntax. Other languages regard this 
as a comparision operation, but Euphoria treats it as a sequence creation
operation. So the precedent has been set for Euphoria to do things in a
different manner from what we are accustomed to in other languages.

The "work around" is to ensure that the LHS has no evaluations to be done
that could be influenced by the RHS.

So in your example code above, you could write ...

  if stack[ib][i] = 0 then
    lLocalTemp = recursive_call(i+1)
    stack[ib][i] = lLocalTemp
  end if

However, now that this new behaviour has been brought to light, I will need
to inspect Win32lib to make sure I'm not doing the undocumented thing.

-- 
Derek Parnell
Melbourne, Australia
irc://irc.sorcery.net:9000/euphoria

new topic     » goto parent     » topic index » view message » categorize

7. Re: Major Bug in Interpreter [Attn: Robert Craig]

After reading the post you made, and doing several runs of my own, I've
come to my own conclusion of how things are working now.

You said, that you would have to make all kinds of checks throughout the
code to make sure you wasn't screwing something up.

To me, after looking at the program logic, both from execution, trial and
error, and my own thoughts on program flow with Euphoria, I can only ask, Why
this behavior was choosen over the default behavior?

And yes, this is Documented in the Reference Manual.

Section: 2.2.4 -> 2.2.9

If you notice, that's the majority of the Sequence refrence, but the
more specific points are this:

Section 2.2.5 Subscripting of Sequences
" A single element of a sequence may be selected by giving the element number in
square brackets. Element numbers start at 1. Non-integer subscripts are rounded
down to an integer.

For example, if x contains {5, 7.2, 9, 0.5, 13} then x[2] is 7.2. Suppose we
assign something different to x[2]:

        x[2] = {11,22,33}

Then x becomes: {5, {11,22,33}, 9, 0.5, 13}. Now if we ask for x[2] we get
{11,22,33} and if we ask for x[2][3] we get the atom 33. If you try to subscript
with a number that is outside of the range 1 to the number of elements, you will
get a subscript error. For example x[0], x[-99] or x[6] will cause errors. So
will x[1][3] since x[1] is not a sequence."


Now why wouldn't this be valid as well, for your addition of the $?

$ should be the last entry into the sequence, at the time of the evaluation of
the lhs, just as with length() shows the length of the sequence at the time of
evaluation.  So, if you do this:

sequence stack
stack = {1,2,3,4}
procedure removeOne()
   stack = stac[1..length(stack)-1]
end procedure

integer i
i = length(stack)
removeOne()
stack[i] = 1


It should error out.  The same should be true for the '$' operator.  I mean,
it would only make sense.  Oviously, the lhs evaluation length() is what we
are wanting, not what we add to it, or remove from it.  If we wanted that,
then we would do that after the assignment, as it has allways been done before.

I'm just trying to make sense of my own ideals of how Euphoria's rules are.
And Derek Parnell is right, this is your interpreter.  I'm just trying to
see the point of trying to account for every possibility, with a single
operator, when it isn't nesscarly needed.

Mario Steele

new topic     » goto parent     » topic index » view message » categorize

8. Re: Major Bug in Interpreter [Attn: Robert Craig]

On 13 Feb 2005, at 12:14, Mario Steele wrote:

> 
> 
> posted by: Mario Steele <eumario at trilake.net>
> 
> Okay, after doing some experimenting, I found what you mean.
> 
> You should word the Documentation, and explination more vividly, then what
> was originally stated:
> 
> In order to recursivly assign something to a sequence, you need to
> in-directly assign the value after the recursive call is made.
> 
> Example:
> }}}
<eucode>
> function recursive_call(integer i)
>     integer ib, id
>     stack &= 0
>     ib = length(stack)
>     for x = 1 to 4 do
>         if stack[ib][i] = 0 then
>             id = recursive_call(i+1)
>             stack[ib][i] = id
>         end if
>     end for
>     return ib
> end function
> </eucode>
{{{

> 
> Which to me, that's a waste of a variable space, that Euphoria is now forced
> to
> have to allocate, and deallocate everytime the function is ran through.
> 
> But anyways, I got it figured out now.  It lends nothing to readability,
> just confusion, and making recursive calls to modify sequences utterly
> useless.

Deja vu all over again. I stopped using Turbo Pascal because of variable-
recursion problems like this.

Kat

new topic     » goto parent     » topic index » view message » categorize

9. Re: Major Bug in Interpreter [Attn: Robert Craig]

Kat wrote:
> On 13 Feb 2005, at 12:14, Mario Steele wrote:
> > But anyways, I got it figured out now.  It lends nothing to readability,
> > just confusion, and making recursive calls to modify sequences utterly
> > useless.
> 
> Deja vu all over again. I stopped using Turbo Pascal because of variable-
> recursion problems like this.

There are no known problems with recursion in Euphoria.

The fact that his example uses recursion is a "red herring".
The incompatibility that we discussed has *nothing* to do with recursion.
It has to do with modifying a variable in two different ways
in the same statement, and expecting it to work a certain way,
even though the manual is silent on the issue. In 2.5 this rare
and weird case now works differently when multiple subscripts
are used on the lhs. The change was needed to efficiently support 
the new $ feature.

Regards,
   Rob Craig
   Rapid Deployment Software
   http://www.RapidEuphoria.com

new topic     » goto parent     » topic index » view message » categorize

10. Re: Major Bug in Interpreter [Attn: Robert Craig]

Robert Craig wrote:
> 
> Kat wrote:
> > On 13 Feb 2005, at 12:14, Mario Steele wrote:
> > > But anyways, I got it figured out now.  It lends nothing to readability,
> > > just confusion, and making recursive calls to modify sequences utterly
> > > useless.
> > 
> > Deja vu all over again. I stopped using Turbo Pascal because of variable-
> > recursion problems like this.
> 
> There are no known problems with recursion in Euphoria.

Only disagreements of how it should work, and the current way is a problem
in the eyes of many.

> The fact that his example uses recursion is a "red herring".
> The incompatibility that we discussed has *nothing* to do with recursion.

Though it *does* affect recursion.

> It has to do with modifying a variable in two different ways
> in the same statement, and expecting it to work a certain way,
> even though the manual is silent on the issue. In 2.5 this rare
> and weird case now works differently when multiple subscripts
> are used on the lhs. The change was needed to efficiently support 
> the new $ feature.

Maybe it's rare, but not weird. I myself think it's obvious that the rhs is
evaluated before the lhs is evaluated and assigned the value of the rhs.
Because that's what the code says. Evaluate the rhs, then assign it to the
lhs.

I don't understand the reason changing that.

Regards, Alexander Toresson

Assembly. Push 'till you pop.

new topic     » goto parent     » topic index » view message » categorize

11. Re: Major Bug in Interpreter [Attn: Robert Craig]

Alexander Toresson wrote:
> 
> Robert Craig wrote:
> > There are no known problems with recursion in Euphoria.
> 
> Only disagreements of how it should work, and the current way is a problem
> in the eyes of many.

I'm not aware of *any* complaints about how recursion is
handled in Euphoria. Please elaborate.

Regards,
   Rob Craig
   Rapid Deployment Software
   http://www.RapidEuphoria.com

new topic     » goto parent     » topic index » view message » categorize

12. Re: Major Bug in Interpreter [Attn: Robert Craig]

> > 
> > Example:
> > }}}
<eucode>
> > function recursive_call(integer i)
> >     integer ib, id
> >     stack &= 0
> >     ib = length(stack)
> >     for x = 1 to 4 do
> >         if stack[ib][i] = 0 then
> >             id = recursive_call(i+1)
> >             stack[ib][i] = id
> >         end if
> >     end for
> >     return ib
> > end function
> > </eucode>
{{{

> > 
> > Which to me, that's a waste of a variable space, that Euphoria is now forced
> > to
> > have to allocate, and deallocate everytime the function is ran through.

Is it actually true that such a temporary, local, variable gets into
the executable? One would think that it'd be optimised away?

-- Another Euphoric, since Nov. 18, 2004 --

new topic     » goto parent     » topic index » view message » categorize

13. Re: Major Bug in Interpreter [Attn: Robert Craig]

Georg Wrede wrote:
> Is it actually true that such a temporary, local, variable gets into
> the executable? One would think that it'd be optimised away?

The time and space used by the extra variable are both 
absolutely trivial, if not zero. Without the extra variable, 
Euphoria would anyway have to create an internal temp variable 
to hold the result.

Regards,
   Rob Craig
   Rapid Deployment Software
   http://www.RapidEuphoria.com

new topic     » goto parent     » topic index » view message » categorize

14. Re: Major Bug in Interpreter [Attn: Robert Craig]

On 15 Feb 2005, at 11:03, Robert Craig wrote:

> 
> 
> posted by: Robert Craig <rds at RapidEuphoria.com>
> 
> Georg Wrede wrote:
> > Is it actually true that such a temporary, local, variable gets into
> > the executable? One would think that it'd be optimised away?
> 
> The time and space used by the extra variable are both 
> absolutely trivial, if not zero. Without the extra variable, 
> Euphoria would anyway have to create an internal temp variable 
> to hold the result.

Ok, lets do that, and save the programmer time and effort remembering it.

Kat

new topic     » goto parent     » topic index » view message » categorize

15. Re: Major Bug in Interpreter [Attn: Robert Craig]

Kat wrote:
> 
> On 15 Feb 2005, at 11:03, Robert Craig wrote:
> > posted by: Robert Craig <rds at RapidEuphoria.com>
> > Georg Wrede wrote:
> > > Is it actually true that such a temporary, local, variable gets into
> > > the executable? One would think that it'd be optimised away?
> > 
> > The time and space used by the extra variable are both 
> > absolutely trivial, if not zero. Without the extra variable, 
> > Euphoria would anyway have to create an internal temp variable 
> > to hold the result.

So, splitting 
stack[ib][i] = function_call_with_side_effects(i+1)


on two lines, like

tmp = function_call_with_side_effects(i+1)
    stack[ib][i] = tmp


is actually "for free"!! Very nice.

There's also the issue of writing non-ambiguous code. Just like
putting a few extra parentheses in complicated logical expressions,
splitting lines like the above just serve the reader of the code.

They make a huge service to all by making it explicit what order
of evaluation we want. Besides, the next guy who has to take over
your code doesn't have to know esoteria and arcana about Euphoria
enough to guess himself what the order of evaluation would be on
a single line. 

(I could cite Stroustrup, Kernighan, Pike, Hunt, Meyers, Wilson,
and others on this, but if this point doesn't get through to all,
it probably wouldn't, even if I looked up the pages and quoted.)

-- Another Euphoric, since Nov. 18, 2004 --

new topic     » goto parent     » topic index » view message » categorize

16. Re: Major Bug in Interpreter [Attn: Robert Craig]

On Tue, 15 Feb 2005 13:58:41 -0800, Georg Wrede <guest at rapideuphoria.com>
wrote:
> }}}
<eucode>
>     tmp = function_call_with_side_effects(i+1)
>     stack[ib][i] = tmp
> </eucode>
{{{

> 
> is actually "for free"!! Very nice.
> 
> There's also the issue of writing non-ambiguous code. Just like
> putting a few extra parentheses in complicated logical expressions,
> splitting lines like the above just serve the reader of the code.
> 
> They make a huge service to all by making it explicit what order
> of evaluation we want. Besides, the next guy who has to take over
> your code doesn't have to know esoteria and arcana about Euphoria
> enough to guess himself what the order of evaluation would be on
> a single line.

I agree, code should be written unambiguously. Rob, it's not possible
to stop someone from creating unreadable code, but it would help the
Euphoria community if a warning was given for ambiguous things like
this - if a variable is modified in the same line as it is referenced.

-- 
MrTrick

new topic     » goto parent     » topic index » view message » categorize

17. Re: Major Bug in Interpreter [Attn: Robert Craig]

Alexander Toresson wrote:
> 
> Robert Craig wrote:
> > 
> > Kat wrote:
> > > On 13 Feb 2005, at 12:14, Mario Steele wrote:
> > > > But anyways, I got it figured out now.  It lends nothing to readability,
> > > > just confusion, and making recursive calls to modify sequences utterly
> > > > useless.
> > > 
> > > Deja vu all over again. I stopped using Turbo Pascal because of variable-
> > > recursion problems like this.
> > 
> > There are no known problems with recursion in Euphoria.
> 
> Only disagreements of how it should work, and the current way is a problem
> in the eyes of many.
> 
> > The fact that his example uses recursion is a "red herring".
> > The incompatibility that we discussed has *nothing* to do with recursion.
> 
> Though it *does* affect recursion.
> 
> > It has to do with modifying a variable in two different ways
> > in the same statement, and expecting it to work a certain way,
> > even though the manual is silent on the issue. In 2.5 this rare
> > and weird case now works differently when multiple subscripts
> > are used on the lhs. The change was needed to efficiently support 
> > the new $ feature.
> 
> Maybe it's rare, but not weird. I myself think it's obvious that the rhs is
> evaluated before the lhs is evaluated and assigned the value of the rhs.
> Because that's what the code says. Evaluate the rhs, then assign it to the
> lhs.
> 
> I don't understand the reason changing that.
> 

>From the disassembly Matt posted, it appears that Eu does no constant folding 
usually. What RC is telling us is that $ uses some constant folding.
When computing s[1][length(s[1])], the interpreter doesn't remember that 
there's a temporary var holding s[1] at the time it parses the second index; 
even worse, the temp was possibly destroyed, so that remembering it wouldn't
help.
Thus, s[1] is fetched once again, which is a waste of CPU cycles.
s[1][$] does remember that s[1] is being subscripted, so that no extra 
time is spent looking twice for s[1] or its length. I remembered an old post
2-3 years ago about about Eu 2.3 not using constant folding as an optimisation 
tool, and found that would explain the story neatly.


CChris

> Regards, Alexander Toresson
> 
> Assembly. Push 'till you pop.
>

new topic     » goto parent     » topic index » view message » categorize

18. Re: Major Bug in Interpreter [Attn: Robert Craig]

On Tue, 15 Feb 2005 08:51:18 -0800, Robert Craig
<guest at RapidEuphoria.com> wrote:

>It has to do with modifying a variable in two different ways
>in the same statement,
Trying not to be toady, but that is an excellent point, not just for
Eu but coding in any language.

Regards,
Pete

new topic     » goto parent     » topic index » view message » categorize

19. Re: Major Bug in Interpreter [Attn: Robert Craig]

A look at the MISRA rules for using the C language is
enough to put anyone off relying on side-effects. Not to
mention many of the most useful standard libraries.

Georg mentioned a Kernighan and Pike (amongst others) a
few posts back.  Here, from K&P's 'The Practice of 
Programming':
str[i++] = str[i++] = ' ';
is likely to give the wrong answer.
Also:
array[i++] = i;
can give varying results.

So the order of evaluation in perhaps the most pervasive
language is not to be relied on.

Fortunately Eu doesn't isn't C; no assigments-as-expressions
here.   Why use C habits dating from the time when compilers
needed help to produce efficient code, in Eu?

Personally, as only a recent and light user, I wouldn't
miss $ if it was removed.

John

new topic     » goto parent     » topic index » view message » categorize

20. Re: Major Bug in Interpreter [Attn: Robert Craig]

Patrick Barnes wrote:

<snip>

> I agree, code should be written unambiguously. Rob, it's not possible
> to stop someone from creating unreadable code, but it would help the
> Euphoria community if a warning was given for ambiguous things like
> this - if a variable is modified in the same line as it is referenced.

I agree, too. Is it actually possible for Euphoria to detect such
ambiguous code? If so, a warning IMHO would be very helpful. Are other
languages capable of displaying a warning in such a situation? If not,
that would give Euphoria another advantage over "normal" languages.

Regards,
   Juergen

new topic     » goto parent     » topic index » view message » categorize

21. Re: Major Bug in Interpreter [Attn: Robert Craig]

Juergen Luethje wrote:
> 
> Patrick Barnes wrote:
> 
> <snip>
> 
> > I agree, code should be written unambiguously. Rob, it's not possible
> > to stop someone from creating unreadable code, but it would help the
> > Euphoria community if a warning was given for ambiguous things like
> > this - if a variable is modified in the same line as it is referenced.
> 
> I agree, too. Is it actually possible for Euphoria to detect such
> ambiguous code? If so, a warning IMHO would be very helpful. Are other
> languages capable of displaying a warning in such a situation? If not,
> that would give Euphoria another advantage over "normal" languages.

I could give a warning, but I think the false-alarm ratio would
be too high for it to be useful. There would often be
dozens or maybe hundreds of variables that might potentially
be overwritten as a result of a function call. It's theoretically
impossible to always know at compile-time whether a given variable
will actually be overwritten at run-time. In many cases the
potential will seem to be there, but in reality it will not happen.

Regards,
   Rob Craig
   Rapid Deployment Software
   http://www.RapidEuphoria.com

new topic     » goto parent     » topic index » view message » categorize

22. Re: Major Bug in Interpreter [Attn: Robert Craig]

On Wed, 16 Feb 2005 07:59:27 -0800, Robert Craig
<guest at rapideuphoria.com> wrote:
> I could give a warning, but I think the false-alarm ratio would
> be too high for it to be useful. There would often be
> dozens or maybe hundreds of variables that might potentially
> be overwritten as a result of a function call. It's theoretically
> impossible to always know at compile-time whether a given variable
> will actually be overwritten at run-time. In many cases the
> potential will seem to be there, but in reality it will not happen.

Maybe hundreds? I don't mean a warning when a global variable might be
modified in a function, I mean a warning where in LHS = RHS(), the LHS
contains global variables that might be modified inside the RHS()
function. I think you can agree that this is the case being discussed,
and it's a problem that cannot be simply resolved by the programmer.

Some examples:
integer i
function do_i()
    i = 20
    return i + 1
end function
i = 10
i = do_i()
}}}
<eucode>
In this case, it's no big deal, i will be rewritten by the function
return anyway - no warning: i = 21

}}}
<eucode>
sequence arr
arr = {1,2,3,4,5}
function rem(integer i)
      arr = arr[1..i-1]&arr[i+1..$]
      return arr
end function
arr = rem(3)

Again, not a problem, as arr is rewritten by the function return - no
warning: arr = {1,2,4,5}


sequence arr
arr = {1,2,3,4,5}
function rem(integer i)
      arr = arr[1..i-1]&arr[i+1..$]
      return i*i
end function
arr[3] = rem(3)

This is a problem, as the LHS has to be resolved... does it refer to
arr before rem() is called, or after? WARNING. If after, arr =
{1,2,9,5}. If before, who knows? Maybe i*i is assigned to an element
that is deleted immediately after...

sequence arr
integer ind
arr = {1,2,3,4,5}
ind = 3
function stuff()
      ind = 2
      return 100
end function
arr[ind] = stuff()

This is a problem, as the subscripting variable is changed by the
function... WARNING
If it's resolved before, arr = {1,2,100,4,5}. If after, arr = {1,100,3,4,5}

sequence arr
integer ind
arr = {1,2,3,4,5}
ind = 3
function stuff()
      arr = {5,4,3,2,1}
      ind = 2
      return 100
end function
arr = arr[1..2] & stuff() & arr[ind]

Hmm, can the RHS ever be ambiguous? Maybe a problem, Rob? WARNING?
Assuming that all the elements are resolved before the function: arr =
{1,2, 100, 3}
Assuming that elements are resolved after the function: arr = {5,4, 100, 4}
Assuming that elements are resolved in their order: arr = {1,2, 100, 4}
Very strange stuff, but it could quite easily happen. A similar
example could occur where the LHS is an atom, with mathematical ops on
the RHS rather than concats.
Another example may occur where in a slice operation: arr[var..func()]
, var is modified by func().



Seems to me, that warnings should occur if:
* The left-hand-side is a sequence AND
* The left-hand-side is subscripted by a variable AND
* That variable is modified by the RHS function

Or
* The left-hand-side is a sequence AND
* The left-hand-side is subscripted by a variable or a literal AND
* The array is modified by the RHS function

Or
* An expression consists of both a variable and a function call
(connected together with concat or mathop, etc) AND
* That function call modifies the variable


I don't think there would be many false positives here... Rob, what
'hundreds' are you talking about?

-- 
MrTrick

new topic     » goto parent     » topic index » view message » categorize

23. Re: Major Bug in Interpreter [Attn: Robert Craig]

Patrick Barnes wrote:
> I don't think there would be many false positives here... Rob, what
> 'hundreds' are you talking about?

When I was implementing this stuff several months ago,
I did some tests, and found that while some examples
were fairly trivial, it quite often turned out, especially
in large Windows prgrams, that a very large number of variables
could potentially be overwritten by a particular function call
used on the RHS of a multiply subscripted assignment.

The reasons for this are:
   1. The function contains calls to other functions and procedures,
      which contain calls to other functions and procedures etc. ...

   2. A call-back can happen whenever Euphoria calls a .dll routine.
      The Euphoria call-back function might modify variables, directly
      or through calls to other routines.

   3. A program might have a forward call via routine id that
      opens up almost all the (non-private) variables in the
      whole program to possible modification

A human might be able to analyze the source code and rule out
the possibility of a routine calling another routine in a given
situation, or a call-back happening, but it's not practical 
for the Euphoria parser to do this.

If you want to experiment with warnings, 
modify source\parser.e to issue a warning 
anytime the variable "dangerous" is set to true.
I think that's essentially what you are after.

Regards,
   Rob Craig
   Rapid Deployment Software
   http://www.RapidEuphoria.com

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu