On Mon, Aug 20, 2012 at 1:20 AM, john skaller <skal...@users.sourceforge.net
> wrote:
> Do you know what it "works"? Because the compiler already
> takes into account the fact that moving an evaluation past a modification
> to a variable it depends on could lead to an unexpected value.
>
> The compiler is already doing what you want in this case.
> Normally it would lazily evaluate y. Note, this is implementation
> dependent: the compiler isn't required to do that at the moment
> with the "specified" semantics.
>
I think semantics are only "specified" if there's a specification written
somewhere.
The problem I originally pointed out is that the analysis does
> not work when closures are involved.
>
This might not be a problem, if the specification is silent on the
semantics of val w.r.t. what values of vars are used when it is evaluated.
> So: I'm well aware of the issue. I don't know how to solve it.**
> But it isn't a bug, because lazy evaluation is allowed for vals.
>
I don't mind lazy evaluation, but I do want the same value back every time.
That's the issue here.
I think if you are using "SSA" form it shouldn't be hard to handle this
kind of thing because the val can reference the "current" value of the vars
it uses at the place where it is initialized. Temporary variables will
automatically be used, if necessary, to support deferred evaluation.
> It may be that there's a better break down of "variable kinds"
> than var/val (and perhaps fun). That's what I was looking at
> with "const". It may be the names "var" and "val" are not the best,
> or that the default shouldn't be "val", but that's not a semantic
> issue but a psychology one (the default is chosen because
> performance in the usual case is better).
>
At some level the distinction could be optional. The compiler should be
able to figure out what is val, var, or "const" based on usage and optimize
appropriately. Even a "var" could be found to be a "const" by the compiler
and optimized as such.
I think the main consideration would be how these things affect programmer
productivity. Having something declared as a val eliminates some stress
around figuring out where to look for a value's definition.
> ** The reason this is very hard is that inlining *by definition
> of the word inlining" means substitution. You replace a call
> with the body of the function being called. You replace
> a parameter with its argument.
>
I think the usual implementation "assigns" all the parameters to their
arguments rather than substitute each parameter for the expression passed
to it. This helps preserve the original semantics.
But in case "val" is the type of a parameter the ambiguity of "val" in
terms of what value of a var is used to evaluate them is going to cause a
problem if something is inlined as a val.
For example in Ocaml:
>
> let cnt = ref 0
> let next () = incr cnt; cnt
> let g x = next(); x ^ string_of_int (!cnt)
>
> let f a b = a ^ b
> print_endline (f (g "a" )(g "b") )
>
> WOOPS! Do you know whether it prints a1b2 or a2b1?
>
> I do. It prints a2b1 because Ocaml evaluates arguments right
> to left. But that's an implementation detail. Its formally unspecified.
>
In C/C++ the order of parameter evaluation is also theoretically
unspecified, and it is unspecified in the case of almost all the operators
except &&, ||, and ?: due to their short-circuit nature.
I can see the parallel you are drawing here between the two - the order of
evaluation is undefined for something like this:
int a=1;
int b=2;
printf("%d %d %d %d", a = b + 1, b = a + 10, a = b + 2, b = a + 3);
One could imagine variations in compilers that might print "17 16 6 4" or
"2 12 14 17" or even something else. Some languages do not allow
assignment within expressions for this reason, it allows this kind of
ambiguity which trips people up. I would probably vote in favor of such a
move in any new language I ran into because it is a simple way to eliminate
this kind of ambiguous code, although it doesn't help much if the
parameters are procedures with side effects, like:
printf("%c%c%c%c, getch(), getch(), getch(), getch());
The above reads 4 characters and prints them in a compiler-dependent order.
Nevertheless, I suspect you'd have specifically enable "risky"
optimisations that reorder parameter evaluations. The default levels like
-O and -O2 I believe will not reorder either calls or assignments in
parameters. Relatively few programmers are actually aware that this is
undefined behavior, so it's safer not to take advantage of it.
If you are interested in designing a programming language for people in
general, it's safe to assume that people will not read and retain the
entire manual. They won't understand or remember all the rules. And if
things don't go the way they expected, and especially if they had to spend
hours trying to figure out some bug that only shows up in the new version
of the compiler .... they go back to Python or Javascript or Ruby
programming because programming in Felix/Ocaml/C++ is "too complicated".
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language