[gameprogrammer] Re: More scripting: Multiple return values

  • From: David Olofson <david@xxxxxxxxxxx>
  • To: gameprogrammer@xxxxxxxxxxxxx
  • Date: Thu, 8 Apr 2004 13:08:31 +0200

On Wednesday 07 April 2004 01.07, Bob Pendleton wrote:
[...]
> > There will be a real vector type eventually, possibly replacing
> > the lightweight LIST type, so it seems logical to just use that
> > instead when you *really* want multiple return values.
>
> I would just go with that. But, consider adding an associative
> vector. One that can be indexed with strings as well as numbers. It
> is really nice to be able to write x =v["x"].

Yep, that's planned as well. However, then I'll have two kinds of 
vectors - unless I just implement index by string as an extra feature 
of the vector type... That should be doable without significant 
overhead when indexing with numbers, right?


[...]
> > Without statically typed function
> > references, all I can do is have the "bytecode" and/or the VM's
> > CALL instruction check that the called function is compatible
> > with the provided arguments, and throw a runtime exception if it
> > isn't.
>
> Yeah, I understand. As an aside the idea of a "virtual machine" can
> be a box that traps the mind. You start thinking that the
> operations need to be like the operations in a "real" computer.
> But, they don't. You can have a "call" byte code that checks
> parameter and return types at run time.

Yeah, that's how I implemented it. There are two instructions (so 
far); CCALL and CALL, where the former expects the compiler to ensure 
that the arguments match the called function (which is grabbed from 
the constant table), and the latter checks everything before calling.


> You can have another
> bytecode that calls OpenGL's glBegin() function if you want.

Yeah, I'm planning on doing that with frequently used stuff. Maybe 
"microthread" sync operations, message passing, some I/O operations 
and stuff. Most of that falls in the "performance hack" domain, 
though.


> I don't know if you are falling into that trap. Just want to point
> it out in case.

I don't think so, but I'm trying to keep the VM as simple as possible, 
within reasonable limits. This is mostly because I want to minimize 
the amount of code that will run in RT context. Still, I tend to 
think "extreme CISC" when it comes to VMs, because of the relatively 
high instruction decoding overhead.


[...]
> > > > A related problem is caused by the fact that I've implemented
> > > > the assignment operator ('=') as an actual operator. That
> > > > means it's handled by the normal infix expression evaluator,
> > > > which in turn means that I can't just look at the left hand
> > > > subexpression to figure out how many arguments I want, in
> > > > case the right hand subexpression happens to be a function
> > > > call. (*If* that's actually desired, that is.)
> > >
> > > Solved above. The assignment operator can inspect the function
> > > signature to determine what it is going to return.
> >
> > Except that operators are only invoked *after* their arguments
> > have been calculated...
>
> Yes, but you can have instructions that check the data type of a
> parameter after it is pushed on the stack and before the call
> instruction. You are designing the machine and the language, you
> can do anything you want to do.

Sure. This is just a matter of whether I make special cases in the 
"expression" rule, or use a dedicated grammar rule for assignments. 
Most grammars I've seen so far do the latter, and I'm starting to 
realize why.

OTOH, if functions return at most one value, this problem goes away, 
since the result of calling a function is identical to that of 
executing an operator opcode. :-) That's why I made "=" a normal 
operator in the first place - but then I got this brilliant idea of 
multiple returns... *hehe*


> You can include all the type
> information in the code following the call instruction. Though when
> I did that I put the information in a block of memory and just put
> a pointer to it after the call instruction. That way it didn't get
> duplicated every time I called a function.

That's pretty much what I'm doing, I think. Every function has an info 
structure generated by the compiler, and that's available to the VM 
as soon as it knows what to call. That's the same info that is used 
by the compiler when verifying hardwired calls.


> >  Function and operator arguments can only be passed
> > by reference or by value.
>
> In your language there are only reference and value parameters.
> There are other kinds of bindings in other languages. Ok, Ok, I
> know that was a very picky comment. :-)

Well, I realize there are other ways as well, but I'm trying to worry 
only about the ones I actually support. ;-)


> > To get around that, I'd have to remove the
> > "=" operator and replace it with a special grammar rule for
> > assignments - which is probably just as well, as "=" is the only
> > operator that treats the left hand term as write-only.
>
> Yeah, that is a problem in a lot of languages. If assignment is an
> operator it has to act like an operator.

Yeah... And it does, so far - except that it never reads the first 
argument; it *writes* to it.

Whether or not it returns a value can be changed very easily. I've 
decided to not have it return a value for now, in order to avoid the 
C/C++ "if(a = b) ..." problem.


> If it is a statement type,
> then you can do all sorts of interesting things with its syntax.

Yes... Well, at least it's a lot easier and cleaner to do weird stuff 
in a dedicated grammar rule than to do it as a special case of the 
expression rule. :-)


> > Anyway, no big deal. I just though it was a good idea to make "="
> > just another operator, but it seems like I was wrong.
>
> That is one of the great debates in language design. I prefer
> having assignment be a statement. That keeps you from writing:
>
>       if (x = NULL)
>
> and spending a week trying to figure out why you are getting a
> segfault... when you meant:
>
>       if (x == NULL)

Well, I just set a flag "NORESULT" when registering the "=" operator, 
which makes the expression rule return a special error code that some 
rules trap. That way I can have C style ++ and -- operators and stuff 
that may or may not be used as subexpressions, depending on what mood 
I'm in. ;-)


//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
|  Free/Open Source audio engine for games and multimedia.  |
| MIDI, modular synthesis, real time effects, scripting,... |
`-----------------------------------> http://audiality.org -'
   --- http://olofson.net --- http://www.reologica.se ---


Other related posts: