Re: Assigning Interface to Object
Speaking of COM.. has anyone successfully used COM interfaces in D2? I once tried to create a DDraw proxy dll but I can't remember how good it worked. https://bitbucket.org/trass3r/ddrawproxy
Why we need scope(success) if I can write at the end?
or what's the differents between theese two: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; scope(success) { std.file.rename(tempFilename, filename); } auto f = File(tempFilename, w); } and: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; auto f = File(tempFilename, w); std.file.rename(tempFilename, filename); }
Type-qualified functions?
How does one avoid code duplication in a snippet code like this: class A{} void foo(const A, void delegate(const A) fn) { // some stuff // ... // ... } void foo(A, void delegate(A) fn) { // exact same stuff, with different qualifiers // ... // ... }
Re: sort and shared
On Thu, 20 Jan 2011 21:14:06 -0500, Adam Conner-Sax adam_conner_...@yahoo.com wrote: The following code: import std.algorithm; class Foo { private: int id_; public: shared int id() const { return id_; } } static bool compare(in shared(Foo) a, in shared(Foo) b) { return (a.id() b.id()); } void main() { shared Foo a,b,c; shared(Foo)[] uFooArray = [a,b,c]; sort!(compare)(uFooArray); } fails to compile with usr/local/src/dmd2/src/phobos/std/conv.d(295): Error: function object.Object.toString () is not callable using argument types () whereas if I just take all the shared away it compiles fine. I imagine that this is somewhere to do with a string function being called on an element of the array and then there's no shared version of that method. Is there a fix? Or a different way to call sort? I can cast away shared for the sort but since in the actual application I have a reason for it, that's a bit worrisome. Thanks! This should be fixed in svn. I encountered a very similar issue, and implemented a fix. This will be fixed in the next release: http://d.puremagic.com/issues/show_bug.cgi?id=4901 -Steve
Re: Why we need scope(success) if I can write at the end?
On 01/21/2011 02:18 PM, tamir wrote: or what's the differents between theese two: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; scope(success) { std.file.rename(tempFilename, filename); } auto f = File(tempFilename, w); } and: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; auto f = File(tempFilename, w); std.file.rename(tempFilename, filename); } I'm a newcomer as well, so take my answer with a good dose of doubt. There is no difference AFAIK. scope(success) allows defining end-of-scope process for a given element --here the file-- in case of success using an idiom consistent with other possible outcomes (read: exit, failure). I find this a Good Thing, personly. Denis _ vita es estrany spir.wikidot.com
Re: sort and shared
Thanks! I tried to apply that patch and rebuild phobos (I changed the file, remade libphobos2.a, put it in /usr/local/lib). That worked but I still get my error. I might have done the applying or rebuilding wrong though, especially since once I did that, even with the casting away of shared, I get some linker errors. I'll wait for the next release, I guess, and in the meantime cast away shared and be very afraid. Is there any way to fix it otherwise by making the elts printable? Adam
Re: sort and shared
On Fri, 21 Jan 2011 10:04:56 -0500, Adam Conner-Sax adam_conner_...@yahoo.com wrote: Thanks! I tried to apply that patch and rebuild phobos (I changed the file, remade libphobos2.a, put it in /usr/local/lib). That worked but I still get my error. I might have done the applying or rebuilding wrong though, especially since once I did that, even with the casting away of shared, I get some linker errors. I'll wait for the next release, I guess, and in the meantime cast away shared and be very afraid. Is there any way to fix it otherwise by making the elts printable? Hm... it's a simple patch. Maybe there is something different I'm not seeing. I'll see if I can reproduce with my build. -Steve
Re: Why we need scope(success) if I can write at the end?
On Fri, 21 Jan 2011 08:18:15 -0500, tamir tamir@gmail.com wrote: or what's the differents between theese two: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; scope(success) { std.file.rename(tempFilename, filename); } auto f = File(tempFilename, w); } and: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; auto f = File(tempFilename, w); std.file.rename(tempFilename, filename); } Look at any linux kernel driver code, and you will see goto used in a very structured way: if(open_port() == -1) goto FAILURE; if(create_device() == -1) goto FAILURE2; if(init_device() == -1) goto FAILURE3; return SUCCESS; FAILURE3: destroy_device(); FAILURE2: close_port(); FAILURE: return ERROR; Basically, this idiom of building a stack of resources that must be destroyed in reverse order on failure is very common in a lot of code. scope(failure) or scope(exit) takes care of these tasks without using gotos, and by reducing the structure required to implement such things: open_port(); // throws exception on failure scope(failure) close_port(); create_device(); scope(failure) destroy_device(); init_device(); Now, scope(success) I believe is less common to require, but it still has the benefit of allowing you to group your dealings with a certain item in one spot. Imagine your code looks more like this: void transactionalCreate(string filename) { string tempFilename = filename ~ .fragment; auto f = File(tempFilename, w); ... // lots of code ... std.file.rename(tempFilename, filename); } It might be easier to follow code that says I'm going to create a temp file, and then at the end, if everything works, I'm going to copy it over the original in one paragraph, rather than have to read the whole function to see what happens to the temp file. It's also easier to write, you just write the scope(success) and never have to worry about special circumstances. You don't have to repeat yourself if you have multiple return statements. You can also return something from a function that may throw an exception without having this silly structure: auto x = fnImGoingToReturnValueOf(); std.file.rename(tempFilename, filename); return x; You can just do return fnImGoingToReturnValueOf(); and scope(success) will ensure your renaming is done properly only if that function doesn't throw. -Steve
Re: sort and shared
On Fri, 21 Jan 2011 10:09:18 -0500, Steven Schveighoffer schvei...@yahoo.com wrote: On Fri, 21 Jan 2011 10:04:56 -0500, Adam Conner-Sax adam_conner_...@yahoo.com wrote: Thanks! I tried to apply that patch and rebuild phobos (I changed the file, remade libphobos2.a, put it in /usr/local/lib). That worked but I still get my error. I might have done the applying or rebuilding wrong though, especially since once I did that, even with the casting away of shared, I get some linker errors. I'll wait for the next release, I guess, and in the meantime cast away shared and be very afraid. Is there any way to fix it otherwise by making the elts printable? Hm... it's a simple patch. Maybe there is something different I'm not seeing. I'll see if I can reproduce with my build. Compiled your code and ran it without error (well, got a segfault because the elements are all null), so I think maybe the patch wasn't applied properly on your machine. I guess all I can recommend is either to get phobos from svn or wait for the next release. -Steve
Re: Type-qualified functions?
On Fri, 21 Jan 2011 09:08:58 -0500, Sean Eskapp eatingstap...@gmail.com wrote: How does one avoid code duplication in a snippet code like this: class A{} void foo(const A, void delegate(const A) fn) { // some stuff // ... // ... } void foo(A, void delegate(A) fn) { // exact same stuff, with different qualifiers // ... // ... } templates: void foo(T)(T, void delegate(T) fn) { } This parameterizes foo based on T, which could be A, const A, or int, or whatever works to compile the function. You could further restrict which templates can be instantiated with a template constraint (say for instance, to restring foo to only instantiate when T is A or const(A) ). -Steve
Re: Source code annotations alla Java
On 1/20/11 5:48 PM, Jacob Carlborg wrote: On 2011-01-20 21:34, Steven Schveighoffer wrote: On Thu, 20 Jan 2011 15:03:55 -0500, Jacob Carlborg d...@me.com wrote: On 2011-01-20 19:18, Steven Schveighoffer wrote: On Thu, 20 Jan 2011 13:07:58 -0500, Jacob Carlborg d...@me.com wrote: On 2011-01-20 15:02, Steven Schveighoffer wrote: On Thu, 20 Jan 2011 08:47:28 -0500, Justin Johansson j...@nospam.com wrote: Not long ago the Java Language people introduced the idea of annotations together with an annotation processing tool (apt). Now perhaps the idea of source code annotations is not actually a Java invention per se, however for someone learning D is there any equivalent idiom [of Java annotations] in the D language? Haven't used Java since they added annotations, but I think they are like C# attributes? In any case, D has an annotation syntax like: @property But I think at the moment, annotations have no custom ability. Only compiler-defined annotations are allowed. This may change in the future, but probably not short-term. FWIW, I think we need a much richer runtime-reflection capability before we can use custom annotations to any great effect. -Steve I would rather formulate it like: currently D has a syntax for keywords that are similar to Java annotations. I don't think it's the same thing. Keywords are not allowed to be used anywhere else, even for things that would parse properly were they not keywords. They are anchors for the parser to determine where it is. In contrast, a compiler-defined annotation is parsed just the same as a custom one, it's just that the meaning is predefined. For example, you can legally do: int property; without error, but this won't even get past the parsing stage: int struct; -Steve I assume you meant int @property;? No. I meant int property; Of course that would work, isn't that like saying this won't work: int struct_; // ? A keyword is specifically not allowed where the grammar would otherwise allow it. A symbol isn't allowed to have @ in it, so this naturally prevents a conflict. I realize the poor example, but it's definitely not a keyword. Otherwise, it would be listed here: http://www.digitalmars.com/d/2.0/lex.html#keyword (actually, are annotations part of the lexical grammar there?). It's more like Object, which is not a keyword, but you aren't allowed to use it to mean anything besides what it means. The end result is, it fails if you use it in the wrong place, but the keyword status makes it fail at the parsing stage. I am not a compiler writer, so I'm talking a bit from my ass here. -Steve Ok, maybe you're right. I'm pretty sure, as you say, that a keyword in the wrong place would fail during parsing. But I don't know where a misplaced annotation/attribute would fail. Jacob is right here. This, as you say, fails: int struct; And also this fails: int @property; So yes, currently @property is just a keyword with a prepended @. Annotations in Java anc C# can have arguments. That is not the case in D. For example, as it is said in DIP6, you could have: @extern('C') void someFunc(); instead of having extern a keyword and thus being unable to use it for identifiers.
Re: Type-qualified functions?
templates: void foo(T)(T, void delegate(T) fn) { } This parameterizes foo based on T, which could be A, const A, or int, or whatever works to compile the function. What if the parameters are more general, for instance the first parameter is always a Foo, the second is a delegate which takes a Foo.Bar, but they're always qualified the same way?
Re: Source code annotations alla Java
On Friday, January 21, 2011 12:36:23 Ary Manzana wrote: On 1/20/11 5:48 PM, Jacob Carlborg wrote: On 2011-01-20 21:34, Steven Schveighoffer wrote: On Thu, 20 Jan 2011 15:03:55 -0500, Jacob Carlborg d...@me.com wrote: On 2011-01-20 19:18, Steven Schveighoffer wrote: On Thu, 20 Jan 2011 13:07:58 -0500, Jacob Carlborg d...@me.com wrote: On 2011-01-20 15:02, Steven Schveighoffer wrote: On Thu, 20 Jan 2011 08:47:28 -0500, Justin Johansson j...@nospam.com wrote: Not long ago the Java Language people introduced the idea of annotations together with an annotation processing tool (apt). Now perhaps the idea of source code annotations is not actually a Java invention per se, however for someone learning D is there any equivalent idiom [of Java annotations] in the D language? Haven't used Java since they added annotations, but I think they are like C# attributes? In any case, D has an annotation syntax like: @property But I think at the moment, annotations have no custom ability. Only compiler-defined annotations are allowed. This may change in the future, but probably not short-term. FWIW, I think we need a much richer runtime-reflection capability before we can use custom annotations to any great effect. -Steve I would rather formulate it like: currently D has a syntax for keywords that are similar to Java annotations. I don't think it's the same thing. Keywords are not allowed to be used anywhere else, even for things that would parse properly were they not keywords. They are anchors for the parser to determine where it is. In contrast, a compiler-defined annotation is parsed just the same as a custom one, it's just that the meaning is predefined. For example, you can legally do: int property; without error, but this won't even get past the parsing stage: int struct; -Steve I assume you meant int @property;? No. I meant int property; Of course that would work, isn't that like saying this won't work: int struct_; // ? A keyword is specifically not allowed where the grammar would otherwise allow it. A symbol isn't allowed to have @ in it, so this naturally prevents a conflict. I realize the poor example, but it's definitely not a keyword. Otherwise, it would be listed here: http://www.digitalmars.com/d/2.0/lex.html#keyword (actually, are annotations part of the lexical grammar there?). It's more like Object, which is not a keyword, but you aren't allowed to use it to mean anything besides what it means. The end result is, it fails if you use it in the wrong place, but the keyword status makes it fail at the parsing stage. I am not a compiler writer, so I'm talking a bit from my ass here. -Steve Ok, maybe you're right. I'm pretty sure, as you say, that a keyword in the wrong place would fail during parsing. But I don't know where a misplaced annotation/attribute would fail. Jacob is right here. This, as you say, fails: int struct; And also this fails: int @property; So yes, currently @property is just a keyword with a prepended @. Annotations in Java anc C# can have arguments. That is not the case in D. For example, as it is said in DIP6, you could have: @extern('C') void someFunc(); instead of having extern a keyword and thus being unable to use it for identifiers. No. No attributes are keywords. The reasoning is simple. A keyword is a word that would be a valid identifier but isn't, because the language treats it as special. @ is not a valid part of an identifier. So, @property can't be a keyword. And property certainly isn't a keyword, since you _can_ use it as an identifier, so it isn't a keyword with @ prepended on either. True, @property is treated as a special symbol by the compiler, and I don't expect that it really treats it like an attribute with the name property (which it will pretty much have to do if we ever get user-defined attributes), but definitely isn't a keyword, because it was never possible for it to be a valid identifier in the first place. - Jonathan M Davis
Re: Why we need scope(success) if I can write at the end?
On Friday, January 21, 2011 05:18:15 tamir wrote: or what's the differents between theese two: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; scope(success) { std.file.rename(tempFilename, filename); } auto f = File(tempFilename, w); } and: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; auto f = File(tempFilename, w); std.file.rename(tempFilename, filename); } scope(success) will be run _regardless_ of how you leave that scope (except for if an exepction is thrown). So, you can have one line with scope(success) and multiple return statements or breaks or continues or whatnot, and that scope(success) statement will be run in all cases. If you didn't use scope(success), then you'd have to duplicate that code at every point that the scope could be exited successfully. Now, if there's only one way to exit a particular scope successfully, then scope(success) is less useful. However, even in cases like that it can improve code maintanence and readability when it comes to stuff like resources. For instance, if you were to open a file at the beginning of a function, having a scope(success) statement immediately following it makes it clear that closing the function has been taken care of, whereas without the scope statement, you'd have to worry about putting it at the end of the function separate from where the file was opened. Having them together makes the code clearer. Now, a file isn't the best example, since you'd want success(exit) in that case, and the File struct std.stdio deals with it anyway through its destructor, but the example should give you the basic idea. - Jonathan M Davis
toString why not const
Hi, I'm trying to override Object's toString. I've noted it isn't a const method, namely: string toString() const; This cause me troubles when using it on a const reference. Shouldn't it be const? Thanks, Tom;
Re: Type-qualified functions?
Sean Eskapp Wrote: templates: void foo(T)(T, void delegate(T) fn) { } This parameterizes foo based on T, which could be A, const A, or int, or whatever works to compile the function. What if the parameters are more general, for instance the first parameter is always a Foo, the second is a delegate which takes a Foo.Bar, but they're always qualified the same way? Their is probably better ways to do this... void main() { foo(new Foo, (int) { }); } void foo(T, U)(T t, void delegate(U) fn) if(__traits(compiles, fn(t.bar))) { } class Foo { int bar() { return 0; } }
Re: toString why not const
Tom Wrote: Hi, I'm trying to override Object's toString. I've noted it isn't a const method, namely: string toString() const; This cause me troubles when using it on a const reference. Shouldn't it be const? Thanks, Tom; Phobos hasn't become very const aware. There have been bugs and things preventing such an effort. So I do believe it should be const, but between the other priorities, and possible signature change for toString, it isn't done yet.
Re: Why we need scope(success) if I can write at the end?
When there are multiple calls that can fail, and where I have to do clean-up code in a certain order and under certain conditions I use scope(exit). For example: import std.stdio; import std.exception; void main() { foo(); } enum NoError = true; bool Initialize() { return true; } bool Start() { return false; } void Terminate() { writeln(Terminated.); } void Stop() { writeln(Stopped.); } void foo() { auto error = Initialize(); enforce(error == NoError, new Exception(Couldn't initialize)); scope(exit) Terminate(); // call Terminate only if Initialize was successful error = Start(); enforce(error == NoError, new Exception(Couldn't start)); scope(exit) Stop(); // call Stop only if Start was successful } If I change the first scope to scope(success), Terminate will not be called if the call to Start() failed. This can be bad in cases where Terminate would release some hardware resource (it can lock up an app, for example). scope statements won't be ran if an exception is throwed before that scope statement is reached. So, that's one thing to keep in mind.
Re: toString why not const
On Friday, January 21, 2011 13:02:56 Tom wrote: Hi, I'm trying to override Object's toString. I've noted it isn't a const method, namely: string toString() const; This cause me troubles when using it on a const reference. Shouldn't it be const? Thanks, Tom; It's a long-standing bug: http://d.puremagic.com/issues/show_bug.cgi?id=1824 In theory, the issues with const in the compiler and in Phobos will be focused on and sorted out not too long after the 64-bit port of dmd has been finished, but regardless, it's still an outstanding issue and definitely annoying. Also, be warned that (due to another bug) you _can't_ declare a struct's toString to be const (it must be _exactly_ string toString() { ... }). You _can_, however, override toString() to be const on classes, though how much good it really does you, I'm not sure. Hopefully all that stuff will be sorted out semi-soon. - Jonathan M Davis
Re: Why we need scope(success) if I can write at the end?
On Friday, January 21, 2011 14:49:44 Andrej Mitrovic wrote: When there are multiple calls that can fail, and where I have to do clean-up code in a certain order and under certain conditions I use scope(exit). For example: import std.stdio; import std.exception; void main() { foo(); } enum NoError = true; bool Initialize() { return true; } bool Start() { return false; } void Terminate() { writeln(Terminated.); } void Stop() { writeln(Stopped.); } void foo() { auto error = Initialize(); enforce(error == NoError, new Exception(Couldn't initialize)); scope(exit) Terminate(); // call Terminate only if Initialize was successful error = Start(); enforce(error == NoError, new Exception(Couldn't start)); scope(exit) Stop(); // call Stop only if Start was successful } If I change the first scope to scope(success), Terminate will not be called if the call to Start() failed. This can be bad in cases where Terminate would release some hardware resource (it can lock up an app, for example). scope statements won't be ran if an exception is throwed before that scope statement is reached. So, that's one thing to keep in mind. That's why you choose the appropriate version of scope(). And while scope(success) is still definitely useful, it's far less useful than scope(failure) or scope(exit). - Jonathan M Davis
Re: Can/should spawn work with functions that return?
On Friday, January 21, 2011 14:12:18 Andrej Mitrovic wrote: import std.stdio; import std.concurrency; void foo(int var) { } bool bar(int var) { return true; } void barWrapper(int var) { bar(var); } void main() { spawn(foo, 1); spawn(barWrapper, 1); spawn(bar, 1); } Errors: testSpawn.d(24): Error: template std.concurrency.spawn(T...) does not match any function template declaration testSpawn.d(24): Error: template std.concurrency.spawn(T...) cannot deduce template function from argument types !()(bool function(int var),int) Of course, when my foreground thread spawns a background thread it doesn't wait for it to finish, so assigning a return value doesn't make much sense. I can see how that can be an error (in any case that error message above is not very informative). But what if I want to spawn a thread with an existing function 'bar' that has side-effects, but I'm not interested in its return value even though it has one? Right now I'm forced to either: a) remove any returns from 'bar' and change it to a void function, which can be really complicated if other functions already depend on its return value, or b) write a new void function that can be called with spawn(), which internally calls 'bar' but discards it's value (so basically it's a wrapper). This is what I've done in the example code. So, is spawning threads on functions that return banned by design? I couldn't read about this anywhere on the D site or TDPL. The current design does not give you any way to access a return value from a spawned function, even if it allowed you to use such a function. And given that fact, it really doesn't make sense conceptually to have spawn work with non-void functions. I'm not sure that there are any technical barriers to it however. Still, as it stands, if a function isn't _designed_ to be called with spawn, I don't see what good it generally does you. If it's not sending messages to the parent thread, then what's the point of calling it? You can't _have_ side effects unless the function alters a shared global. I do have an enhancement request related to getting return values from spawned functions though: http://d.puremagic.com/issues/show_bug.cgi?id=4566 - Jonathan M Davis
Re: toString why not const
Jesse Phillips: So I do believe it should be const, but between the other priorities, and possible signature change for toString, it isn't done yet. There also the idea of introducing the writeTo() standard method, that's neat :-) Bye, bearophile
Re: Can/should spawn work with functions that return?
Sorry, I should be careful with the word side-effects. What I meant was the newly spawned thread does its own job that the main thread doesn't care much about. It doesn't touch main's state or any shared variables. It does some work other than return a value. But the function I wanted the new thread to execute happened to have a return value, so I couldn't spawn the thread. Really, the issue is that sometimes I have to convert C code to D and concurrency is dealt with differently in the two languages, not to mention the fact that I have next to no experience with using threads in any language (but I'm forced to use them in some cases). So, sometimes I'll ask silly questions because I'm very new to this, but hopefully I'll learn a thing or two. I do enjoy your long and informative responses though, Jonathan. :)
Re: Why we need scope(success) if I can write at the end?
On 01/21/2011 09:56 PM, Jonathan M Davis wrote: On Friday, January 21, 2011 05:18:15 tamir wrote: or what's the differents between theese two: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; scope(success) { std.file.rename(tempFilename, filename); } auto f = File(tempFilename, w); } and: void transactionalCreate(string filename) { string tempFilename = filename - .fragment; auto f = File(tempFilename, w); std.file.rename(tempFilename, filename); } scope(success) will be run _regardless_ of how you leave that scope (except for if an exepction is thrown). So, you can have one line with scope(success) and multiple return statements or breaks or continues or whatnot, and that scope(success) statement will be run in all cases. If you didn't use scope(success), then you'd have to duplicate that code at every point that the scope could be exited successfully. Now, if there's only one way to exit a particular scope successfully, then scope(success) is less useful. However, even in cases like that it can improve code maintanence and readability when it comes to stuff like resources. For instance, if you were to open a file at the beginning of a function, having a scope(success) statement immediately following it makes it clear that closing the function has been taken care of, whereas without the scope statement, you'd have to worry about putting it at the end of the function separate from where the file was opened. Having them together makes the code clearer. Now, a file isn't the best example, since you'd want success(exit) in that case, and the File struct std.stdio deals with it anyway through its destructor, but the example should give you the basic idea. - Jonathan M Davis I just realised scope(success) can avoid 2 kinds of bugs, one common, one naughty: * at first coding time, simply forgetting releasing resources (one thinks at that when accessing it, but then, it's easy to forget), or any other exit task * at maintenance time, opening a new exit point for a function (new return), and forgetting the exit task there Denis _ vita es estrany spir.wikidot.com
const-typed class does not have const members
The following code yields results as commented. import std.stdio; class A { int b; } void main() { const A a = new A; writeln(typeof(a).stringof); // const(A) writeln(typeof(a.b).stringof); // const(int) writeln((const A).stringof); // const(A) writeln(typeof((const A).b).stringof); // int } Given this information, how do I work around this in templates? I'd like a template which can type its params based on members of T, for instance: void foo(T)(T x, typeof(T.member) y) but this will yield non-const second parameters even if T is const. Help anybody?
Re: const-typed class does not have const members
Sean Eskapp wrote: The following code yields results as commented. import std.stdio; class A { int b; } void main() { const A a = new A; writeln(typeof(a).stringof); // const(A) writeln(typeof(a.b).stringof); // const(int) writeln((const A).stringof); // const(A) writeln(typeof((const A).b).stringof); // int } Given this information, how do I work around this in templates? I'd like a template which can type its params based on members of T, for instance: void foo(T)(T x, typeof(T.member) y) but this will yield non-const second parameters even if T is const. Help anybody? Ironically, parameter list is not a useful place to constraint the parameter types. At the least, you probably want some conversions. If so, would this work: import std.traits; void foo(T, M)(T x, M m) if (isImplicitlyConvertible!(M, typeof(T.member))) {} class C { int member; } void main() { auto c = new C; foo(c, 42); } If you want to ensure that the member is assignable, you can try this: import std.traits; void foo(T, M)(T x, M m) if (__traits(compiles, { x.member = m; })) {} class C { int member; } void main() { const auto c = new C; // -- compilation error foo(c, 42); } But the error message is only somewhat helpful: deneme.d(26369): Error: template deneme.foo(T,M) if (__traits(compiles,delegate () { x.member = m; } )) does not match any function template declaration deneme.d(26369): Error: template deneme.foo(T,M) if (__traits(compiles,delegate () { x.member = m; } )) cannot deduce template function from argument types !()(const(C),int) Ali
Re: Can/should spawn work with functions that return?
On Friday, January 21, 2011 15:23:37 Andrej Mitrovic wrote: Sorry, I should be careful with the word side-effects. What I meant was the newly spawned thread does its own job that the main thread doesn't care much about. It doesn't touch main's state or any shared variables. It does some work other than return a value. But the function I wanted the new thread to execute happened to have a return value, so I couldn't spawn the thread. Really, the issue is that sometimes I have to convert C code to D and concurrency is dealt with differently in the two languages, not to mention the fact that I have next to no experience with using threads in any language (but I'm forced to use them in some cases). So, sometimes I'll ask silly questions because I'm very new to this, but hopefully I'll learn a thing or two. I do enjoy your long and informative responses though, Jonathan. :) Well, I'd suggest just wrapping the function call in a lambda, unless spawn doesn't like that for some reason. I suppose that spawn could be made take functions with return values, but it's not generally something that you'd do, and it _is_ pretty easy to wrap such functions, so it seems to me like it's probably better as it is - though I can see why it would be annoying if you kept needing to spawn functions with return values. Still, that makes me wonder about what you're doing. I guess that you could be doing I/O or somethnig, but you certainly can't be talking back to the parent thread without having written things that way (in which case, you'd have made the spawned function void). You could always put in an enhancement request, though it does seem wrong to me (conceptually-speaking, if nothing else) to have a spawned function with a return value. - Jonathan M Davis