↑ ↓ ← → Andy Friesen <andy ikagames.com>
writes:
I happened upon this language just yesterday. I think I'm in love. :>
First, the bad news. This little snippet can crash the compiler:
alias void delegate() SimpleDelegate;
SimpleDelegate[] funcarray;
....
funcarray[]();
The error message is:
Assertion failure: '!ident' on line 1812 in file 'mtype.c'
I'm not sure whether it should be legal D or not, but it probably
shouldn't crash the compiler in either case. :)
Second up, there's no explicit scope operator like C++ has, so there's
no way to call a global function from within a class that has a method
by the same name. The most obvious example is the toString function in
the string module. Copying C++ is an unappealing option, since D's only
scope operator is a period, which would be a tad ambigious, not to
mention ugly.
Lastly, a few tiny suggestions. How about coroutines? They have a way
of reducing the complexity of state machines. Python implements
coroutines as iterators, which you can use in a for statement.
Templates that accept a variable number of arguments would be nice too,
though the syntax might start to get weird at that point. (arrays of types?)
Anyway, thanks for finally letting me stop bouncing between begging for
C++'s power, and C#'s simplicity. ;)
-- Andy Friesen
↑ ↓ ← → Burton Radons <loth users.sourceforge.net>
writes:
Andy Friesen wrote:
I happened upon this language just yesterday. I think I'm in love. :>
First, the bad news. This little snippet can crash the compiler:
alias void delegate() SimpleDelegate;
SimpleDelegate[] funcarray;
....
funcarray[]();
The error message is:
Assertion failure: '!ident' on line 1812 in file 'mtype.c'
I'm not sure whether it should be legal D or not, but it probably
shouldn't crash the compiler in either case. :)
Hm. On the one hand, I do a lot of dispatching to lists of delegates;
on the other hand, there's no speed benefit in the compiler optimising
it for us, and the return from the operation isn't clear (a list of the
return value, as with map?).
Second up, there's no explicit scope operator like C++ has, so there's
no way to call a global function from within a class that has a method
by the same name. The most obvious example is the toString function in
the string module. Copying C++ is an unappealing option, since D's only
scope operator is a period, which would be a tad ambigious, not to
mention ugly.
Use the module name you used to import:
import string;
...
string.toStringz (xxx);
If the symbol exists in this module, alias it into something more
explicit in the global scope or import your own module and use that name.
Lastly, a few tiny suggestions. How about coroutines? They have a way
of reducing the complexity of state machines. Python implements
coroutines as iterators, which you can use in a for statement.
You'll need to be more explicit about what they are, how you think
they'd work in a D context, what they'd be capable of.
↑ ↓ ← → Andy Friesen <andy ikagames.com>
writes:
Burton Radons wrote:
Andy Friesen wrote:
I happened upon this language just yesterday. I think I'm in love. :>
First, the bad news. This little snippet can crash the compiler:
alias void delegate() SimpleDelegate;
SimpleDelegate[] funcarray;
....
funcarray[]();
The error message is:
Assertion failure: '!ident' on line 1812 in file 'mtype.c'
I'm not sure whether it should be legal D or not, but it probably
shouldn't crash the compiler in either case. :)
Hm. On the one hand, I do a lot of dispatching to lists of delegates;
on the other hand, there's no speed benefit in the compiler optimising
it for us, and the return from the operation isn't clear (a list of the
return value, as with map?).
Second up, there's no explicit scope operator like C++ has, so there's
no way to call a global function from within a class that has a method
by the same name. The most obvious example is the toString function
in the string module. Copying C++ is an unappealing option, since D's
only scope operator is a period, which would be a tad ambigious, not
to mention ugly.
Use the module name you used to import:
import string;
...
string.toStringz (xxx);
If the symbol exists in this module, alias it into something more
explicit in the global scope or import your own module and use that name.
Lastly, a few tiny suggestions. How about coroutines? They have a
way of reducing the complexity of state machines. Python implements
coroutines as iterators, which you can use in a for statement.
You'll need to be more explicit about what they are, how you think
they'd work in a D context, what they'd be capable of.
At the core, a coroutine is basically a function that stores its state
somewhere other than the stack so that one can later "resume" the
function after it returns.
for (int i=0; i<10; i++)
return i; // won't work, but it'd be nice
A better explanation, and an inventive C implementation can be found at
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
To paraphrase, it's sometimes useful to have two functions that jump
back and forth, instead of having one strictly call the other. Writing
one of the functions as a state machine is one way to solve this
problem. Coroutines are a better way. :) (it's also easy to use them
for quick n' dirty cooperative threading)
As for how they could work in D, I think Python has the right idea.
"somewhere other than the stack" would be an iterator object. (one with
a method to fetch the next value) Internally, local variables are
stored within the iterator itself. A StopIteration exception is raised
when the coroutine function has completed whatever it's doing.
This (rather bizzare) Python function produces the fibonacci sequence,
for example:
def fib():
a = 0
b = 1
while True:
yield b
c = a + b
a = b
b = c
The actual function returns an iterator, which one would hold onto,
calling its next() method when desired.
f = fib()
i = 0
try:
while i < 10:
print f.next()
i += 1
except StopIteration:
pass # do nothing
This particular coroutine goes on forever, so the exception handling in
this example is extraneous. It's left in for clarity.
The trickiest part of doing this in D is the iterator itself. One way
is to have a "special" template interface for iterators.
coroutine int fib()
{
int a = 0;
int b = 1;
int c = b;
while (true)
{
yield b;
c = a + b;
a = b;
b = c;
}
}
instance Iterator(int) IntIter;
IntIter.Iterator f = fib();
try
{
for (int i=0; i < 10; i++)
printf("%i\n", f.next());
}
catch (StopIteration)
{ }
I think an Iterator.atend() method would be better than throwing an
exception, as exceptions imply some kind of error condition, which isn't
really the case. "return" could be used instead of "yield", but it may
be better to distinguish the two.
On a slightly related note, iterators could be provided for arrays and
such as well, allowing a foreach() construct to be added to the language
easily.
The downsides are pretty obvious -- having a "magical" template
interface built into the language, and the compiler complexity imposed
by having some locals on the stack, and other locals stored in an iterator.
whew!
-- Andy Friesen
↑ ↓ ← → Mark Evans <Mark_member pathlink.com>
writes:
P.S. You can go back several months and read my posts here about the Icon
language, which supports coroutines natively. They have their uses.
http://www.cs.arizona.edu/icon/
http://unicon.sourceforge.net/index.html
Mark
At the core, a coroutine is basically a function that stores its state
somewhere other than the stack so that one can later "resume" the
function after it returns.