December 10, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to davidl | 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 Overflow No, 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#ForeachStatements > MDCL 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 ;) >> http://www.dsource.org/projects/minid/wiki/LanguageSpec2/Functions#Coroutines And again, there's the link I gave you last time. Please read up on it. |
December 11, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | 在 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: >> 在 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. > 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. >> MDCL stack overflowed out, maybe mdcl should do something to protect itself from stack overflowing. > > Maybe it should ;) > Of course it's your responsibility to improve it. :D And a commercial quality MiniD interpreter should not overflow out. :D >> 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 ;) > 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. > 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. |
December 11, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to davidl | 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 ;) |
December 11, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | 在 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: >> 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. > 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. |
December 11, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to davidl | 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. |
December 13, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
On Wed, Dec 10, 2008 at 11:45 PM, Jarrett Billingsley <jarrett.billingsley@gmail.com> wrote: >> 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 they are now :) |
December 14, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | 在 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: >>> 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 they are now :) > 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. |
December 14, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to davidl | 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 class I'm not familiar with what a "case class" is, could you demonstrate? > 2.threading I'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. |
December 14, 2008 Re: MiniD 2 - Tentative Release Candidate 1 | ||||
---|---|---|---|---|
| ||||
On Sun, Dec 14, 2008 at 12:09 AM, Jarrett Billingsley <jarrett.billingsley@gmail.com> wrote: >> 2.threading > > I'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. Erm, not necessarily SMP, just preemptive multithreading. Probably not going to be added, ever. |
Copyright © 1999-2021 by the D Language Foundation