digitalmars.D.announce - MiniD 2 - Tentative Release Candidate 1
- Jarrett Billingsley (80/80) Dec 07 2008 ffs, if I don't release it now I'll _never_ release it.
- mpt (30/30) Dec 08 2008 Great stuff, but I have some trouble with the binding lib.
- Jarrett Billingsley (13/43) Dec 08 2008 Fixed.
- mpt (31/51) Dec 08 2008 Fix compiles for the explicitly defined ctor, but not for the default.
- Jarrett Billingsley (25/55) Dec 08 2008 There shouldn't be much different, at least from the point of view of
- davidl (5/86) Dec 09 2008 I've learned a bit minid today.
- Jarrett Billingsley (10/14) Dec 09 2008 Ah, but you can. Coroutines have an opApply, and are therefore
- davidl (5/21) Dec 09 2008 I got an impression that a scripting lang coroutine is less expensive th...
- Jarrett Billingsley (41/44) Dec 09 2008 The cost of a coroutine object in MiniD, as well as the cost of
- davidl (86/132) Dec 10 2008 It's cool it could be used in that syntax. But I find nowhere of docs de...
- Jarrett Billingsley (65/151) Dec 10 2008 Yeah, you do. I gave you a link in my last post. See at the end? Go
- davidl (59/125) Dec 10 2008 Ah, I thought it were another page I've read carefully. Yet that was act...
- Jarrett Billingsley (44/90) Dec 10 2008 I'm not sure that's a good idea. The compiler does already issue an
- davidl (34/55) Dec 10 2008 Umm, I misunderstood the function expression system in MiniD. I didn't e...
- Jarrett Billingsley (12/18) Dec 11 2008 Right; it's more like a Fiber from Tango (and is implemented using
- Jarrett Billingsley (3/11) Dec 13 2008 And they are now :)
- davidl (7/20) Dec 13 2008 Cool, I've learned Scala a bit that I miss several things in scala.
- Jarrett Billingsley (4/7) Dec 13 2008 I'm sorry but I don't think SMP will ever make it into the language.
- Jarrett Billingsley (4/7) Dec 13 2008 Erm, not necessarily SMP, just preemptive multithreading. Probably
ffs, if I don't release it now I'll _never_ release it. After over a year of work, a few drastic changes, and a completely new implementation, I give you: MiniD 2. http://dsource.org/projects/minid --------------------------------- What's new in the language? - Lots. - Several syntactic changes and additions leading to much cleaner-looking, terser code. - Classes and instances have been greatly improved, thanks to a one-year trip into the land of prototype-based objects. - More metamethods for more object customizability. In particular, field access and method calls can be intercepted, and there is now a full complement of arithmetic operator overloads (including reverse versions). - Weak references. - A new type which can hold instances of D classes, for use by native code. - Sixty-four (64) bit integers. What will *you* do with all those bits? - A much-expanded and improved standard library. - Much more well-defined semantics for most language constructs and operations. - A more flexible module loading system. --------------------------------- What's this new implementation? - It's waaaaaaaaaAAAy better than the old one. This is really the killer feature of MiniD 2. - It has its own garbage collector, meaning that your scripts won't trigger native app GC cycles (well.. much, much less often), and MiniD code also runs much faster. - It has a completely new API that is similar to the Lua or Squirrel APIs. - There Is One Way To Do It. The old implementation and API were hole-y and inconsistent. Now, you're pretty much locked into doing things one way, meaning much less chance for error and much less to learn. - Virtually anything you can do in the language, you can do in the API without much difficulty. The new API is much more well-rounded than the old one. - Performancewise, it beats the pants off of Python, though that's not _necessarily_ saying much. I don't know how it measures up to Lua as I don't have a way of measuring Lua's performance from within the language (so as to exclude startup and compilation times), but I get the impression that it's pretty close in some cases. --------------------------------- What do I need to compile it? - Tango, SVN revision 4048. I *told* you this was a tentative release candidate. I don't know if it'll work with any older/newer ones. - DMD 1.034 or newer, or equivalent. LDC seems to work as well. GDC does not. Sorry Mac users, go get David to work on GDC again ;) - Some kind of build tool, DSSS/rebuild or bu[il]d. - MiniD itself. Just check out the head revision of the MiniD trunk at http://svn.dsource.org/projects/minid/trunk. - The understanding that if you are on Linux and try to do all sorts of stupid fancy stuff with symbolic links and putting things in nonstandard directories and making directories read-only, I will not have any sympathy for you when you can't get D, Tango, DSSS, or MiniD to work correctly. The D toolchain is fragile enough as it is, please don't bend it. --------------------------------- Why am I calling this a tentative release candidate? - Some aspects of the library (THE BINDING LIBRARY, which is much better than MiniD 1's, and the compiler to an extent) have not been very heavily tested and are likely to be somewhat buggy. But I'm one guy with limited time and so if you could start using it and making it fail that'd be just great. - Some of the docs are not yet complete. The section on modules is not yet complete, but not a whole lot has changed there anyway. The DDocs for the individual API modules are basically complete but are somewhat lacking in more complex examples, which is what the tutorials are supposed to be for. - I haven't compiled it on Linux recently. Yeah, I should do that more often. But it worked last month or so. --------------------------------- What is needed before an "official" release is made? - Time, something I don't have a lot of this week. After that, I have three weeks of bliss. - Testing. - Finished docs. - Maybe a couple more additions/changes. --------------------------------- Anything else? - Mudkip.
Dec 07 2008
Great stuff, but I have some trouble with the binding lib. 1. If I don't wrap a constructor, I get an error: minid/bind.d(1101): static assert "Cannot call default constructor for class Foo; please wrap a constructor explicitly" 2. If I wrap a constructor with no parameters (i.e. WrapCtors!(void function())), I get an error: minid/bind.d(1066): constructor minid.bind.WrappedClass!(Foo,"Foo","",WrapCtors!(void function()),WrapMethod!(Call)).WrappedClass.ClassCtorShims!(void function()).this (MDVM*,()) does not match parameter types () minid/bind.d(1066): Error: expected 1 arguments, not 0 3. I can't find an obvious way to initialize global variables, so I try superPush, which gives a runtime error: minid.types.MDException: <no location available>: newInstance - expected 'class' for base, not 'null' Test code below: import minid.bind; import minid.api; class Foo { this() {} this(int i) {} void Call() {} } void main() { MDVM vm; auto t = openVM(&vm); loadStdlibs(t); WrapGlobals!( WrapType!( Foo, "Foo", WrapCtors!(void function(int)), WrapMethod!(Foo.Call) ) )(t); superPush(t, new Foo()); newGlobal(t, "myfoo"); }
Dec 08 2008
On Mon, Dec 8, 2008 at 3:44 AM, mpt <foo invalid.x> wrote:Great stuff, but I have some trouble with the binding lib.Good! Because I wasn't ;)1. If I don't wrap a constructor, I get an error: minid/bind.d(1101): static assert "Cannot call default constructor for class Foo; please wrap a constructor explicitly"Fixed.2. If I wrap a constructor with no parameters (i.e. WrapCtors!(void function())), I get an error: minid/bind.d(1066): constructor minid.bind.WrappedClass!(Foo,"Foo","",WrapCtors!(void function()),WrapMethod!(Call)).WrappedClass.ClassCtorShims!(void function()).this (MDVM*,()) does not match parameter types () minid/bind.d(1066): Error: expected 1 arguments, not 0Fixed.3. I can't find an obvious way to initialize global variables, so I try superPush, which gives a runtime error:You're actually doing it right, unless you wanted to instantiate the wrapped MiniD class, in which case it'd be more like: pushGlobal(t, "Foo"); // get the global class Foo pushNull(t); // make room for 'this' rawCall(t, -2, 1); // call the class to instantiate it (1 return for the instance) newGlobal(t, "myfoo"); // save it in the global myfoominid.types.MDException: <no location available>: newInstance - expected 'class' for base, not 'null'Fixed.Test code below: import minid.bind; import minid.api; class Foo { this() {} this(int i) {} void Call() {} } void main() { MDVM vm; auto t = openVM(&vm); loadStdlibs(t); WrapGlobals!( WrapType!( Foo, "Foo", WrapCtors!(void function(int)), WrapMethod!(Foo.Call) ) )(t); superPush(t, new Foo()); newGlobal(t, "myfoo"); }This code now works, just svn up your MiniD installation :)
Dec 08 2008
Jarrett Billingsley wrote:On Mon, Dec 8, 2008 at 3:44 AM, mpt <foo invalid.x> wrote:Fix compiles for the explicitly defined ctor, but not for the default. This code gives: minid/bind.d(1110): Error: no super class constructor for Foo import minid.bind; import minid.api; class Foo {} void main() { MDVM vm; auto t = openVM(&vm); loadStdlibs(t); WrapGlobals!( WrapType!( Foo, "Foo" ) )(t); }Great stuff, but I have some trouble with the binding lib.Good! Because I wasn't ;)1. If I don't wrap a constructor, I get an error: minid/bind.d(1101): static assert "Cannot call default constructor for class Foo; please wrap a constructor explicitly"Fixed.I can't see the difference between superPush-created myfoo and one created by your example. superPush doc says it creates MiniD-converted objects, but they're not usable. superPush(t, new Foo()); newGlobal(t, "myfoo"); runString(t, "myfoo.Call();"); This gives: "tango.core.Exception.AssertException ../extern/minid/minid/bind.d(1397): Invalid 'this' parameter passed to method Foo.Call" Your example works, but it's not what I need. I want to create the Foo object in D myself and pass it to MiniD and call its methods. Ideally, I'd like to have/write a function like void setGlobal(Type)(MDThread* t, char[] name, Type value) to create and modify global variables.3. I can't find an obvious way to initialize global variables, so I try superPush, which gives a runtime error:You're actually doing it right, unless you wanted to instantiate the wrapped MiniD class, in which case it'd be more like: pushGlobal(t, "Foo"); // get the global class Foo pushNull(t); // make room for 'this' rawCall(t, -2, 1); // call the class to instantiate it (1 return for the instance) newGlobal(t, "myfoo"); // save it in the global myfoo
Dec 08 2008
On Mon, Dec 8, 2008 at 3:22 PM, mpt <mpt iki.fi> wrote:Fix compiles for the explicitly defined ctor, but not for the default. This code gives: minid/bind.d(1110): Error: no super class constructor for Foo import minid.bind; import minid.api; class Foo {} void main() { MDVM vm; auto t = openVM(&vm); loadStdlibs(t); WrapGlobals!( WrapType!( Foo, "Foo" ) )(t); }Fixed.I can't see the difference between superPush-created myfoo and one created by your example. superPush doc says it creates MiniD-converted objects, but they're not usable.There shouldn't be much different, at least from the point of view of the MiniD code. If you want to know, the difference is that instances of the wrapped class created using MiniD are actually instances of a class that is _derived_ from the class you wrapped, whereas instances of the class you push are instances of the original class. But the binding library is *supposed* to abstract that away ;)superPush(t, new Foo()); newGlobal(t, "myfoo"); runString(t, "myfoo.Call();"); This gives: "tango.core.Exception.AssertException ../extern/minid/minid/bind.d(1397): Invalid 'this' parameter passed to method Foo.Call"Fixed.Your example works, but it's not what I need. I want to create the Foo object in D myself and pass it to MiniD and call its methods. Ideally, I'd like to have/write a function like void setGlobal(Type)(MDThread* t, char[] name, Type value) to create and modify global variables.The implementation of that might be: void SetGlobal(Type)(MDThread* t, char[] name, Type value) { superPush(t, value); if(findGlobal(t, name)) { swap(t); fielda(t, -2, name); pop(t); } else newGlobal(t, name); } This will create a global if it doesn't already exist, and will update an existing global. If you want it to always update an existing global, it simply becomes "superPush(t, value); setGlobal(t, name);".
Dec 08 2008
I've learned a bit minid today. I'm curious why foreach opApply don't use the yield instead of the current implementation? and another curious thing is how can I serialize/deserialize minid object in minid? any .tupleof for class available? 在 Mon, 08 Dec 2008 13:50:47 +0800,Jarrett Billingsley <jarrett.billingsley gmail.com> 写道:ffs, if I don't release it now I'll _never_ release it. After over a year of work, a few drastic changes, and a completely new implementation, I give you: MiniD 2. http://dsource.org/projects/minid --------------------------------- What's new in the language? - Lots. - Several syntactic changes and additions leading to much cleaner-looking, terser code. - Classes and instances have been greatly improved, thanks to a one-year trip into the land of prototype-based objects. - More metamethods for more object customizability. In particular, field access and method calls can be intercepted, and there is now a full complement of arithmetic operator overloads (including reverse versions). - Weak references. - A new type which can hold instances of D classes, for use by native code. - Sixty-four (64) bit integers. What will *you* do with all those bits? - A much-expanded and improved standard library. - Much more well-defined semantics for most language constructs and operations. - A more flexible module loading system. --------------------------------- What's this new implementation? - It's waaaaaaaaaAAAy better than the old one. This is really the killer feature of MiniD 2. - It has its own garbage collector, meaning that your scripts won't trigger native app GC cycles (well.. much, much less often), and MiniD code also runs much faster. - It has a completely new API that is similar to the Lua or Squirrel APIs. - There Is One Way To Do It. The old implementation and API were hole-y and inconsistent. Now, you're pretty much locked into doing things one way, meaning much less chance for error and much less to learn. - Virtually anything you can do in the language, you can do in the API without much difficulty. The new API is much more well-rounded than the old one. - Performancewise, it beats the pants off of Python, though that's not _necessarily_ saying much. I don't know how it measures up to Lua as I don't have a way of measuring Lua's performance from within the language (so as to exclude startup and compilation times), but I get the impression that it's pretty close in some cases. --------------------------------- What do I need to compile it? - Tango, SVN revision 4048. I *told* you this was a tentative release candidate. I don't know if it'll work with any older/newer ones. - DMD 1.034 or newer, or equivalent. LDC seems to work as well. GDC does not. Sorry Mac users, go get David to work on GDC again ;) - Some kind of build tool, DSSS/rebuild or bu[il]d. - MiniD itself. Just check out the head revision of the MiniD trunk at http://svn.dsource.org/projects/minid/trunk. - The understanding that if you are on Linux and try to do all sorts of stupid fancy stuff with symbolic links and putting things in nonstandard directories and making directories read-only, I will not have any sympathy for you when you can't get D, Tango, DSSS, or MiniD to work correctly. The D toolchain is fragile enough as it is, please don't bend it. --------------------------------- Why am I calling this a tentative release candidate? - Some aspects of the library (THE BINDING LIBRARY, which is much better than MiniD 1's, and the compiler to an extent) have not been very heavily tested and are likely to be somewhat buggy. But I'm one guy with limited time and so if you could start using it and making it fail that'd be just great. - Some of the docs are not yet complete. The section on modules is not yet complete, but not a whole lot has changed there anyway. The DDocs for the individual API modules are basically complete but are somewhat lacking in more complex examples, which is what the tutorials are supposed to be for. - I haven't compiled it on Linux recently. Yeah, I should do that more often. But it worked last month or so. --------------------------------- What is needed before an "official" release is made? - Time, something I don't have a lot of this week. After that, I have three weeks of bliss. - Testing. - Finished docs. - Maybe a couple more additions/changes. --------------------------------- Anything else? - Mudkip.
Dec 09 2008
On Tue, Dec 9, 2008 at 3:58 AM, davidl <davidl 126.com> wrote:I've learned a bit minid today. I'm curious why foreach opApply don't use the yield instead of the current implementation?Ah, but you can. Coroutines have an opApply, and are therefore iterable using foreach. See the section on coroutines (http://www.dsource.org/projects/minid/wiki/LanguageSpec2/Functions#Coroutines) for some info on that. Using coroutines for iteration is more powerful, but of course the price you pay is that they're a lot more expensive than a function closure.and another curious thing is how can I serialize/deserialize minid object in minid? any .tupleof for class available?Sure, have a look of fieldsOf/allFieldsOf in the base library (http://www.dsource.org/projects/minid/wiki/StdLib2/BaseLib). They'll give you functions as well, but it's easy to skip over them.
Dec 09 2008
在 Tue, 09 Dec 2008 21:07:46 +0800,Jarrett Billingsley <jarrett.billingsley gmail.com> 写道:On Tue, Dec 9, 2008 at 3:58 AM, davidl <davidl 126.com> wrote:I got an impression that a scripting lang coroutine is less expensive than a function call? I guess coroutine in a scripting interpreted lang won't require any thread involved, and the suspension of the execution maybe even more costless compared to a return statement and reexecution of that function in the case of opApply. And I'm still not able to get opApply to work with coroutines, any example available? I always get the error message of "Iterated coroutine must be in the initial state", I've no clue about what it's going on.I've learned a bit minid today. I'm curious why foreach opApply don't use the yield instead of the current implementation?Ah, but you can. Coroutines have an opApply, and are therefore iterable using foreach. See the section on coroutines (http://www.dsource.org/projects/minid/wiki/LanguageSpec2/Functions#Coroutines) for some info on that. Using coroutines for iteration is more powerful, but of course the price you pay is that they're a lot more expensive than a function closure.thanks, that's helpful. MiniD is way more powerful than I've thought.and another curious thing is how can I serialize/deserialize minid object in minid? any .tupleof for class available?Sure, have a look of fieldsOf/allFieldsOf in the base library (http://www.dsource.org/projects/minid/wiki/StdLib2/BaseLib). They'll give you functions as well, but it's easy to skip over them.
Dec 09 2008
On Wed, Dec 10, 2008 at 12:12 AM, davidl <davidl 126.com> wrote:I got an impression that a scripting lang coroutine is less expensive than a function call? I guess coroutine in a scripting interpreted lang won't require any thread involved, and the suspension of the execution maybe even more costless compared to a return statement and reexecution of that function in the case of opApply.The cost of a coroutine object in MiniD, as well as the cost of calling it, depends on the compilation options (http://www.dsource.org/projects/minid/wiki/API2/CompilationOptions). If you don't specify any version flags when compiling MiniD, it will use tango Fibers for coroutines created from native functions, and will use its own system of pausing and resuming for coroutines created from MiniD functions. The cost of a coroutine resume/yield is more than a normal function call, but it's still not a lot. For example, using MiniD coroutines, I can perform around 1.6 million resume/yield pairs per second on my Pentium M. Fibers aren't much slower; I still get about 1.25 million. That's not going to be a bottleneck considering the speed of most other operations. Rather, the biggest cost with a coroutine is memory. A coroutine object is relatively large compared to a function closure, and depending on the compilation options, can also allocate D heap memory. So for simple iteration tasks, it might be in the interest of performance to try to write it in the form of a function iterator, and if it gets to be too complex to be worth it, you can write it as a coroutine.And I'm still not able to get opApply to work with coroutines, any example available? I always get the error message of "Iterated coroutine must be in the initial state", I've no clue about what it's going on.When you use foreach on a coroutine, it has to be in the "initial" state. The only times a coroutine can be in an initial state is (1) immediately after they are created, before they are called even once, and (2) after they have died and then had their .reset() method called. A simple example: function count(x) = coroutine function() { yield() // first "empty" yield is important for foreach-able coroutines for(i: 1 .. x + 1) yield(i) // yield values after that // when this coroutine returns here, iteration stops } foreach(v; count(4)) writeln(v) // prints 1 through 4 Notice that count is returning a new coroutine object each time you call it, so the coroutine is always in the "initial" state. There's more info on coroutines, including showing some iterators and explaining their various states, at the following link: http://www.dsource.org/projects/minid/wiki/LanguageSpec2/Functions#Coroutines
Dec 09 2008
在 Wed, 10 Dec 2008 13:52:18 +0800,Jarrett Billingsley <jarrett.billingsley gmail.com> 写道:On Wed, Dec 10, 2008 at 12:12 AM, davidl <davidl 126.com> wrote:It's cool it could be used in that syntax. But I find nowhere of docs describing this feature? Do I miss something? Actually I tried something like: module test global v=coroutine function() { local opApply=coroutine function opApply(m) { local i=0 if (i<3) { i++ yield(i) } return null } yield() } v() foreach(m;v)writefln(m) In the case I wrote, the coroutine foreach just conflicts with the coroutine foreach way you illustrate in your example. As I didn't have that information, I tried to perform my coroutine foreach in a standardized opApply way. That's somewhat confusing for people not having the knowledge of coroutine foreach. Intuitively, the foreach is presumably working in the way of calling instance's opApply func and passing the arg of reverse or not to it. While the truth is I'm wrong. The inconsistency seems to be a tradeoff. Yes, without opApply it looks clean. While it's inconsistent. That means developers who use minid need to learn more. The following case illustrates a easily misread code for me at least. In minid, I thought the parentheses were compulsive, cause the coroutinefunc.state won't work, but coroutinefunc.state(). So in such case, I guess the "count" refers to the function object, while the result shows it just endless loop and results stack overflow. Even that "count" actually a function call without the arg, the calling is performed. that's somehow misleading. function count(x) { function opApply(m) = coroutine function opApply(m) { for(i: 1 .. x + 1) yield(i) // yield values after that return null } foreach(v;count) writeln(v) // prints 1 through 4 } count(4) object.Exception: Stack Overflow MDCL stack overflowed out, maybe mdcl should do something to protect itself from stack overflowing. I'm trying to use coroutine foreach in a class. class count { x =3 function opApply(m) = coroutine function opApply(m) { yield() for(i: 1 .. m.x + 1) yield(i) } } global c= count() foreach(v;c.opApply(c)) writeln(v) // prints 1 through 4 it causes of runtime error: Error: opApply(7): Attempting to access field 'x' from a value of type 'null' The problem here is I misuseing the function definition. function opApply(m) = coroutine function opApply() works OK. But that's inconsistent from a strong type user's view. Because the left part is function with 1 arg, right part is a coroutine function without any arg. That's pretty error-prone for newbies. Also the class coroutine foreach tries as follows failed: class count { x =3 function opApply(m) = coroutine function opApply() { writefln(m) // prints null, that's pretty astonishing for me. for(i: 1 .. x + 1) yield(i) } } global c= count() foreach(v;c) writeln(v) // prints 1 through 4 the result is printing nothing, and no runtime error. If I modify the loop to for(i: 1 .. :x + 1) yield(i) runtime error shows up: Error: opApply(7): Attempting to access field 'x' from a value of type 'null' Seems there's no easy way of using coroutine foreach with class instance?I got an impression that a scripting lang coroutine is less expensive than a function call? I guess coroutine in a scripting interpreted lang won't require any thread involved, and the suspension of the execution maybe even more costless compared to a return statement and reexecution of that function in the case of opApply.The cost of a coroutine object in MiniD, as well as the cost of calling it, depends on the compilation options (http://www.dsource.org/projects/minid/wiki/API2/CompilationOptions). If you don't specify any version flags when compiling MiniD, it will use tango Fibers for coroutines created from native functions, and will use its own system of pausing and resuming for coroutines created from MiniD functions. The cost of a coroutine resume/yield is more than a normal function call, but it's still not a lot. For example, using MiniD coroutines, I can perform around 1.6 million resume/yield pairs per second on my Pentium M. Fibers aren't much slower; I still get about 1.25 million. That's not going to be a bottleneck considering the speed of most other operations. Rather, the biggest cost with a coroutine is memory. A coroutine object is relatively large compared to a function closure, and depending on the compilation options, can also allocate D heap memory. So for simple iteration tasks, it might be in the interest of performance to try to write it in the form of a function iterator, and if it gets to be too complex to be worth it, you can write it as a coroutine.And I'm still not able to get opApply to work with coroutines, any example available? I always get the error message of "Iterated coroutine must be in the initial state", I've no clue about what it's going on.When you use foreach on a coroutine, it has to be in the "initial" state. The only times a coroutine can be in an initial state is (1) immediately after they are created, before they are called even once, and (2) after they have died and then had their .reset() method called. A simple example: function count(x) = coroutine function() { yield() // first "empty" yield is important for foreach-able coroutines for(i: 1 .. x + 1) yield(i) // yield values after that // when this coroutine returns here, iteration stops } foreach(v; count(4)) writeln(v) // prints 1 through 4Notice that count is returning a new coroutine object each time you call it, so the coroutine is always in the "initial" state. There's more info on coroutines, including showing some iterators and explaining their various states, at the following link: http://www.dsource.org/projects/minid/wiki/LanguageSpec2/Functions#Coroutines
Dec 10 2008
On Wed, Dec 10, 2008 at 3:15 AM, davidl <davidl 126.com> wrote:$B:_(B Wed, 10 Dec 2008 13:52:18 +0800$B!$(BJarrett Billingsley <jarrett.billingsley gmail.com> $B<LF;(B: It's cool it could be used in that syntax. But I find nowhere of docs describing this feature? Do I miss something?Yeah, you do. I gave you a link in my last post. See at the end? Go there and read all about it.Actually I tried something like: module test global v=coroutine function() { local opApply=coroutine function opApply(m) { local i=0 if (i<3) { i++ yield(i) } return null } yield() } v() foreach(m;v)writefln(m)No wonder it didn't work, it's completely the wrong way to do it. ;)In the case I wrote, the coroutine foreach just conflicts with the coroutine foreach way you illustrate in your example. As I didn't have that information, I tried to perform my coroutine foreach in a standardized opApply way. That's somewhat confusing for people not having the knowledge of coroutine foreach. Intuitively, the foreach is presumably working in the way of calling instance's opApply func and passing the arg of reverse or not to it. While the truth is I'm wrong.The thing is, it _does_ work by calling the coroutine's opApply. It's just that you don't define opApply yourself. Think about it - you don't put an opApply in an array to foreach over it. How can you opApply over it? Because array.opApply is defined by the standard library. The same thing for coroutines. http://www.dsource.org/projects/minid/wiki/StdLib2/ThreadLib#Threadmetamethods That shows where opApply is defined for thread (coroutine) objects. Which again links to the page I gave you in my last post.The inconsistency seems to be a tradeoff. Yes, without opApply it looks clean. While it's inconsistent. That means developers who use minid need to learn more.Again, it's not inconsistent, as coroutines _do_ have an opApply.The following case illustrates a easily misread code for me at least. In minid, I thought the parentheses were compulsive, cause the coroutinefunc.state won't work, but coroutinefunc.state(). So in such case, I guess the "count" refers to the function object, while the result shows it just endless loop and results stack overflow. Even that "count" actually a function call without the arg, the calling is performed. that's somehow misleading. function count(x) { function opApply(m) = coroutine function opApply(m) { for(i: 1 .. x + 1) yield(i) // yield values after that return null } foreach(v;count) writeln(v) // prints 1 through 4 } count(4) object.Exception: Stack OverflowNo, it's just that you don't understand MiniD's iteration protocol. I'm not going to explain it here because I've already explained it - two or three times - in the documentation. Long story short, 'count' refers to the global function 'count' which you already defined. Functions are first-class values, so "count" refers to the function object itself, like doing "&count" in D. Foreach loops are based on an iterator function, and so when you do foreach(v; count) it thinks "count" is your iterator function. It calls it, which makes a recursive call, which calls itself, and so on. For information on the iteration protocol, read this: http://www.dsource.org/projects/minid/wiki/LanguageSpec2/Statements#ForeachStatementsMDCL stack overflowed out, maybe mdcl should do something to protect itself from stack overflowing.Maybe it should ;)I'm trying to use coroutine foreach in a class. class count { x =3 function opApply(m) = coroutine function opApply(m) { yield() for(i: 1 .. m.x + 1) yield(i) } } global c= count() foreach(v;c.opApply(c)) writeln(v) // prints 1 through 4 it causes of runtime error: Error: opApply(7): Attempting to access field 'x' from a value of type 'null'Well yeah. Where is your coroutine getting the value 'm'? It's not. So it gets 'null'.The problem here is I misuseing the function definition. function opApply(m) = coroutine function opApply() works OK.Yes, because of upvalues. When you take the parameter off the coroutine, 'm' then refers to the local variable in the outer function.But that's inconsistent from a strong type user's view. Because the left part is function with 1 arg, right part is a coroutine function without any arg. That's pretty error-prone for newbies.And coroutines and iterators are pretty advanced. So I'm not so sure I much mind what the newbies think ;) Actually you're again doing it wrong. You don't have to manually pass the object to be iterated to opApply, it's already passed as 'this'. The following: class count { x = 3 function opApply() { local m = this return (coroutine function() { yield() for(i: 1 .. m.x + 1) yield(i) }).opApply() // hee hee } } global c = count() foreach(v; c) writeln(v) // prints 1 through 4 Works without having to call c.opApply directly. What I did in the method there is a trick - if you want one opApply to actually iterate over another object, you can just return the values from _its_ opApply. I put 'this' in m so that the coroutine could access it (because functions can't access their outer function's 'this'). I then create the coroutine function and call opApply on it, returning those values, so the foreach loop ends up iterating over the coroutine.Also the class coroutine foreach tries as follows failed: class count { x =3 function opApply(m) = coroutine function opApply() { writefln(m) // prints null, that's pretty astonishing for me.Again, where is 'm' coming from? It's null because you didn't pass anything. The object on which opApply is called is in 'this'.for(i: 1 .. x + 1) yield(i) } } global c= count() foreach(v;c) writeln(v) // prints 1 through 4 the result is printing nothing, and no runtime error. If I modify the loop to for(i: 1 .. :x + 1) yield(i) runtime error shows up: Error: opApply(7): Attempting to access field 'x' from a value of type 'null'That's because 'this' in the opApply is null.Seems there's no easy way of using coroutine foreach with class instance?No, you're just doing it wrong ;)And again, there's the link I gave you last time. Please read up on it.http://www.dsource.org/projects/minid/wiki/LanguageSpec2/Functions#Coroutines
Dec 10 2008
在 Wed, 10 Dec 2008 21:52:01 +0800,Jarrett Billingsley <jarrett.billingsley gmail.com> 写道:On Wed, Dec 10, 2008 at 3:15 AM, davidl <davidl 126.com> wrote:Ah, I thought it were another page I've read carefully. Yet that was actually a page that I read by skim. I should have read it up carefully. Sorry for that.在 Wed, 10 Dec 2008 13:52:18 +0800,Jarrett Billingsley <jarrett.billingsley gmail.com> 写道: It's cool it could be used in that syntax. But I find nowhere of docs describing this feature? Do I miss something?Yeah, you do. I gave you a link in my last post. See at the end? Go there and read all about it.Of course it's your responsibility to improve it. :D And a commercial quality MiniD interpreter should not overflow out. :DMDCL stack overflowed out, maybe mdcl should do something to protect itself from stack overflowing.Maybe it should ;)That's not true. All about compiler is easeing developers. Why not issue a compiler error/warning when it reaches some code like: function opApply(m) = coroutine function opApply(m) 1. the local var m shadows the arg m _in 1 declaration_ 2. this could be a general mistake which could possibly be made by people with a strong type programming background Probing this kind of code seems troublesome, I will be glad to see MiniD can give an error on this kind of code someday.I'm trying to use coroutine foreach in a class. class count { x =3 function opApply(m) = coroutine function opApply(m) { yield() for(i: 1 .. m.x + 1) yield(i) } } global c= count() foreach(v;c.opApply(c)) writeln(v) // prints 1 through 4 it causes of runtime error: Error: opApply(7): Attempting to access field 'x' from a value of type 'null'Well yeah. Where is your coroutine getting the value 'm'? It's not. So it gets 'null'.The problem here is I misuseing the function definition. function opApply(m) = coroutine function opApply() works OK.Yes, because of upvalues. When you take the parameter off the coroutine, 'm' then refers to the local variable in the outer function.But that's inconsistent from a strong type user's view. Because the left part is function with 1 arg, right part is a coroutine function without any arg. That's pretty error-prone for newbies.And coroutines and iterators are pretty advanced. So I'm not so sure I much mind what the newbies think ;)Actually you're again doing it wrong. You don't have to manually pass the object to be iterated to opApply, it's already passed as 'this'. The following: class count { x = 3 function opApply() { local m = this return (coroutine function() { yield() for(i: 1 .. m.x + 1) yield(i) }).opApply() // hee hee } } global c = count() foreach(v; c) writeln(v) // prints 1 through 4 Works without having to call c.opApply directly. What I did in the method there is a trick - if you want one opApply to actually iterate over another object, you can just return the values from _its_ opApply. I put 'this' in m so that the coroutine could access it (because functions can't access their outer function's 'this'). I then create the coroutine function and call opApply on it, returning those values, so the foreach loop ends up iterating over the coroutine.That's pretty tricky. But the syntax of following is cleaner if possible: class count { x = 3 coroutine function opApply() //mark it as a coroutine function. { yield() for(i: 1 .. :x + 1) yield(i) } } global c = count() foreach(v; c) writeln(v) // prints 1 through 4 It's pretty sad "coroutine function" in a whole doesn't work. But still opApply() = coroutine function() still not work You do it: function f()=coroutine function() I think if MiniD is able to do the syntax I proposed, I wouldn't have those bunch questions about foreach on a coroutine function. And People won't expect do foreach on a coroutine in most cases if that syntax comes true. Because for most people, a coroutine opApply is more intuitive than a coroutine with an opApply method available. And I think it's practicle for MiniD compiler decide what to do, because MiniD can probe that if the opApply method is coroutine or not. If it's coroutine function, than implicitly a coroutine context created. Also the first yield is quite weird for me. class count { x = 3 function opApply() = coroutine function() //mark it as a coroutine function. { yield() // I hope that we could get rid of the first yield, is that for something special or else? for(i: 1 .. :x + 1) yield(i) } } global c = count() foreach(v; c) writeln(v) // current it prints nothing. I don't know what it's actually going here.
Dec 10 2008
On Wed, Dec 10, 2008 at 10:21 PM, davidl <davidl 126.com> wrote:That's not true. All about compiler is easeing developers. Why not issue a compiler error/warning when it reaches some code like: function opApply(m) = coroutine function opApply(m) 1. the local var m shadows the arg m _in 1 declaration_ 2. this could be a general mistake which could possibly be made by people with a strong type programming background Probing this kind of code seems troublesome, I will be glad to see MiniD can give an error on this kind of code someday.I'm not sure that's a good idea. The compiler does already issue an error if you declare a local multiple times in the same function: local x { local x // error, shadows previous declaration } But if that is generalized to disallowing local variable declarations that shadow locals in any enclosing functions as well, .. ech. It seems a bit much. I might implement it, I might not.That's pretty tricky. But the syntax of following is cleaner if possible: class count { x = 3 coroutine function opApply() //mark it as a coroutine function. { yield() for(i: 1 .. :x + 1) yield(i) } } global c = count() foreach(v; c) writeln(v) // prints 1 through 4 It's pretty sad "coroutine function" in a whole doesn't work.I think you're confused about what "coroutine" is, grammatically. "coroutine" is an expression. Much like "-" in front of "5" gives the number "-5", "coroutine" in front of an expression that evaluates to a function gives a thread object. Allowing something like "coroutine function" as a declaration is inflexible. Most of the time, the parameters to the coroutine are not going to be the same as the parameters to the function which creates it. It seems like syntactic noise for little benefit.But still opApply() = coroutine function() still not work You do it: function f()=coroutine function()..you don't have a body on that function. Of course it's not going to work.I think if MiniD is able to do the syntax I proposed, I wouldn't have those bunch questions about foreach on a coroutine function. And People won't expect do foreach on a coroutine in most cases if that syntax comes true. Because for most people, a coroutine opApply is more intuitive than a coroutine with an opApply method available.I've considered making coroutines a basic iterable type, in which case their opApply would disappear. (it would also make the "dummy" first index disappear.)And I think it's practicle for MiniD compiler decide what to do, because MiniD can probe that if the opApply method is coroutine or not. If it's coroutine function, than implicitly a coroutine context created. Also the first yield is quite weird for me.The first yield is there so that any extra parameters to the coroutine object are passed before iteration starts, as well as to associate the context ('this') parameter with it.class count { x = 3 function opApply() = coroutine function() //mark it as a coroutine function.Again I think you're getting a bit confused as to what "coroutine" is doing. opApply is not a "coroutine function". opApply is a function which returns a thread object. That is, function opApply() = coroutine function() {} is equivalent to: function opApply() { local function blah() {} return coroutine blah }{ yield() // I hope that we could get rid of the first yield, is that for something special or else? for(i: 1 .. :x + 1) yield(i) } } global c = count() foreach(v; c) writeln(v) // current it prints nothing. I don't know what it's actually going here.I'll agree that that's a bit surprising. What actually happens is that on the first iteration, it notices that 'c' is not a function, so it calls c.opApply(). It then happily assumes that opApply returned a function, and calls it. That is, it doesn't notice opApply returned a coroutine, and so doesn't call opApply on the coroutine itself. It calls the coroutine, thinking it's a function, and the coroutine yields nothing, which the foreach loop interprets as "end of iteration." Agh. I'm liking the idea of making 'thread' a basic iterable type more and more ;)
Dec 10 2008
在 Thu, 11 Dec 2008 12:45:19 +0800,Jarrett Billingsley <jarrett.billingsley gmail.com> 写道:On Wed, Dec 10, 2008 at 10:21 PM, davidl <davidl 126.com> wrote:Umm, I misunderstood the function expression system in MiniD. I didn't expect a function expression system just thinking that the assignment is just assign a func literal to the left hand side as a declaration. Because in D you can do a lot coding like following: void delegate() f= void delegate(){ } It's obvious for you as the MiniD creator to distinguish the difference. But I doubt for normal developer, they could be somewhat confused. I think a little bit special rule should be added: function f() = function f(){} ///disallowed function f() = function f_exp(){} // allowed It's a safer rule for people to rename the function with another name, this is more clear that for a developer realizing that, he's not doing something like I had thought "I assigned a named func literal to the l-value in the declaration, which is similar to the D code style". And I can hardly see any very bad restriction this could result. And in my opinion such function expression literal can even be restricted that it doesn't own a name. Because in such case a name doesn't do any good. For people want to return a named literal, they just simply rewrite it to: function f() { return function f_exp(){} // allow the named function expressoin literal here } function f() = function f_exp(){} // under stricter rule, f_exp is not allowed. you write it: function f() = function (){} Please correct me here, if I'm wrong. Another thing is I really didn't pay attention to parallel in MiniD. So , the thread is not tradition thread in D? It's actually just a coroutine? I just thought that coroutine was implemented as several different MiniD interpret context for each coroutine, and resume a coroutine just simply resuming that interpret context which could be very costless. And the thread I though could be some native threads with several MiniD interpreters working.That's not true. All about compiler is easeing developers. Why not issue a compiler error/warning when it reaches some code like: function opApply(m) = coroutine function opApply(m) 1. the local var m shadows the arg m _in 1 declaration_ 2. this could be a general mistake which could possibly be made by people with a strong type programming background Probing this kind of code seems troublesome, I will be glad to see MiniD can give an error on this kind of code someday.I'm not sure that's a good idea. The compiler does already issue an error if you declare a local multiple times in the same function: local x { local x // error, shadows previous declaration } But if that is generalized to disallowing local variable declarations that shadow locals in any enclosing functions as well, .. ech. It seems a bit much. I might implement it, I might not.
Dec 10 2008
On Thu, Dec 11, 2008 at 2:06 AM, davidl <davidl 126.com> wrote:Another thing is I really didn't pay attention to parallel in MiniD. So , the thread is not tradition thread in D? It's actually just a coroutine?Right; it's more like a Fiber from Tango (and is implemented using Fibers depending on the compilation options).I just thought that coroutine was implemented as several different MiniD interpret context for each coroutine, and resume a coroutine just simply resuming that interpret context which could be very costless.You're actually right, in a way; each thread object is its own _interpreter_, which has a call stack and locals. But each thread is _not_ its own VM; that is, all threads share the same globals and data can be freely passed between them. In MiniD, coroutine == thread. "coroutine" creates a thread object.And the thread I though could be some native threads with several MiniD interpreters working.MiniD was not designed with symmetric multithreading as a goal. However, it would still be possible to make a library which you could use to create and use other VMs from within MiniD. It's been done with Lua.
Dec 11 2008
On Wed, Dec 10, 2008 at 11:45 PM, Jarrett Billingsley <jarrett.billingsley gmail.com> wrote:And they are now :)I think if MiniD is able to do the syntax I proposed, I wouldn't have those bunch questions about foreach on a coroutine function. And People won't expect do foreach on a coroutine in most cases if that syntax comes true. Because for most people, a coroutine opApply is more intuitive than a coroutine with an opApply method available.I've considered making coroutines a basic iterable type, in which case their opApply would disappear. (it would also make the "dummy" first index disappear.)
Dec 13 2008
在 Sat, 13 Dec 2008 23:05:03 +0800,Jarrett Billingsley <jarrett.billingsley gmail.com> 写道:On Wed, Dec 10, 2008 at 11:45 PM, Jarrett Billingsley <jarrett.billingsley gmail.com> wrote:Cool, I've learned Scala a bit that I miss several things in scala. 1.Case class 2.threading I think those two important features should be considered. With those two I think it's more sophicated to bind with some GUI interface. And there , a more active GUI based development could be possible.And they are now :)I think if MiniD is able to do the syntax I proposed, I wouldn't have those bunch questions about foreach on a coroutine function. And People won't expect do foreach on a coroutine in most cases if that syntax comes true. Because for most people, a coroutine opApply is more intuitive than a coroutine with an opApply method available.I've considered making coroutines a basic iterable type, in which case their opApply would disappear. (it would also make the "dummy" first index disappear.)
Dec 13 2008
On Sat, Dec 13, 2008 at 11:53 PM, davidl <davidl 126.com> wrote:Cool, I've learned Scala a bit that I miss several things in scala. 1.Case classI'm not familiar with what a "case class" is, could you demonstrate?2.threadingI'm sorry but I don't think SMP will ever make it into the language. It is open-source, so you're free to modify it and add it if you want.
Dec 13 2008
On Sun, Dec 14, 2008 at 12:09 AM, Jarrett Billingsley <jarrett.billingsley gmail.com> wrote:Erm, not necessarily SMP, just preemptive multithreading. Probably not going to be added, ever.2.threadingI'm sorry but I don't think SMP will ever make it into the language. It is open-source, so you're free to modify it and add it if you want.
Dec 13 2008