pbr vs multiple returns
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Jan 10, 2007
- 612 views
cchris005 wrote: > > > Subject: Re: Digest for EUforum at topica.com, issue 6333 > > > > > > posted by: Pete Lomax <petelomax at blueyonder.co.uk> > > > > CChris wrote: > > > }}} <eucode> > > > function pop(byref sequence stack) > > > object top > > > top=stack[$] > > > stack=stack[1..$-1] > > > return top > > > end function > > > </eucode> {{{ > > > > > Currently, you need to return both the modified stack and the former top > > > element, which is awkward. > > > > FWIW, I plan something like: > > }}} <eucode> > > function[2] pop(sequence stack) > > return stack[$], stack[1..$-1] > > end function > > > > {nextitem,stack}=pop(stack) > > </eucode> {{{ > > > > > More generally, PBR enables to transform an object, rather to return a > > > modified object which you have to copy onto the original - waste of CPU. > > Technically, I plan an "unnecessary" dword move which "true" pbr > > wouldn't; but that is trivial overhead compared to existing cow semantics > > (in fact so trivial I very much doubt it would ever show on any timing > > test). > > > > Would that "dword move" also work when transforming a subscripted > quantity, like (3]? Hopefully, I'll know more when I start implementing it, see below. > > And, by the way, would you really expect to get the modified stack in > the returned value? I probably programmed too much in asm, but I find > this a bit confusing. And you have to perform an extra s1=s[1] to get > the value you need. You seem to be confusing
return stack[$],stack[1..$-1]
with
return {stack[$],stack[1..$-1]}
So, no, I don't expect to get the modified stack "in" "the" return value, I expect to get the modified stack as the second return value. Internally, I plan to implement eg:
function[2] pop(sequence stack) return stack[$], stack[1..$-1] end function {nextitem,stack}=pop(stack)
as something similar to (pseudocode):
object fres1,fres2 -- virtual, of course sequence popstack -- scoped to pop, "" pop: fres1=popstack[$] fres2=popstack[1..$-1] ret popstack=stack stack=<no value> call pop top=fres1 stack=fres2
When I said "mov dword" I was referring to the last two statements, a neglible and insignificant cost for avoiding cow overheads. Going back to a[i]=update(a[i]), I expect that to be frighteningly difficult to fully optimise with this multiple returns approach and may need real pbr. But anyway, I think multiple returns are a pretty neat feature in their own right, albeit not quite as flexible as true pbr. > Your proposal doesn't look very good to me. Maybe not. Let me just add that it seems Rob has gone to great lengths to optimise say x=append(x,...) and I feel that optimisation should be generalised so it applies to user code, not just a handful of builtins. > > > > > > Eu has function pointers, using call_back(routine_id(rt_name)). What > > > confuses me is why I can't do it with variables. Am I the only one? > > > > Firstly, as background, a routine_id is *utterly meaningless* to any > > other than call_func, call_proc, and call_back. Agreed? > > > > True. What is the issue? I think I was trying to say that you'd never pass a routine_id to a c func, unless you intend to have it passed back to Eu code, as C code cannot do anything with it. Likewise variable_id would be no use to C code. I was just trying to set the scene and make it clear I was not talking about var_id but raw_address(var_id). > Did you ever try to allow an external dll/piece of code to access an Eu > variable? And do you think this is not right? I've always used raw blocks of memory when dealing with C code. > Using a get_this_var()/set_this_var(typeof_this_var x) pair for every > such variable looks really like a bad idea to me. That's how we wind up > doing it unfortunately. Well it seems to me that call_back(get_var) and call_back(set_var) would be the only way you could possibly manipulate Eu vars from C code. Very tricky but at least possible. See below. > > Admittedly, you an also alloocate an address (isn't this a raw pointer?) Yes but it is not an Eu variable. > and use this for interfacing. Only problem is that peek/poke are so darn > slow... Separate issue. > > But indeed, my primary point was: there's a routine_id, why is a > variable_id() any more complicated? Hence why is it not implemented? It is a shed load more complicated. You don't modify routines. They don't move about. If you do x=append(x,x) then almost always x will have been shifted somewhere else in memory. Consider string s="text". In assembly this goes something like: dd 4 ; length dd 0x82000001 ; type and refcount data db "text",0 align 4 s dd (data+1) ror 2 (see execute.h for Eu implementation, which shifts 3 and uses different high bits, etc) So, say we get the actual address of s and pass it to a C function. Is it goiing to know what to do with it? Does it understand the types? Will it honour the refcounts and clone things when needed? Will it maintain length (and base and postfill)? When the C code craps on things, is the Eu backend going to cope/give intelligible error messages? Will it promise not to make circular references? Will it typecheck things it modifies? And so on. Open this up and you completely destabalise the backend. If you get to a point in some C code where you want to modify some Eu vars, you are far better off invoking a call_back and doing it in Eu, imo. The same is probably true if you just want to subscript an Eu var in C. Regards, Pete