digitalmars.D - assert() vs. enforce(), invariant() vs. ... ?
- Joseph Rushton Wakeling (29/29) Aug 29 2013 Hello all,
- Jacob Carlborg (17/20) Aug 29 2013 You can quite easily create a wrapper for that.
- Artur Skawina (18/40) Aug 29 2013 Hard-coded unconditional invariants does not seem very useful, and, as
- Joseph Rushton Wakeling (3/15) Aug 29 2013 Interesting. When it comes down to it, it looks like what you're propos...
- Jacob Carlborg (5/7) Aug 29 2013 It is a proxy. What's the point of a proxy if not to add some additional...
- Joseph Rushton Wakeling (6/8) Aug 29 2013 No, I mean std.typecons.Proxy:
- Jacob Carlborg (5/11) Aug 29 2013 Oh, that Proxy. What's the point of it? The example looks like just an
- John Colvin (3/16) Aug 30 2013 alias this, but without implicit conversion. It just implements
- Jacob Carlborg (4/6) Aug 30 2013 So what's the difference to Typedef, declared just below?
- John Colvin (6/11) Aug 30 2013 Typedef uses Proxy to do the work. Proxy is a mixing template for
- Jacob Carlborg (4/9) Aug 30 2013 Ok, I see.
- Namespace (7/20) Aug 30 2013 What was the initial reason, to move typedef from the language
- John Colvin (20/45) Aug 30 2013 I believe typedef was deprecated due to no-one being able to
- Namespace (2/21) Aug 30 2013 I don't understand the difference to alias myInt = int;
- Joseph Rushton Wakeling (3/5) Aug 30 2013 alias means it's a different name for the same type -- typedef should me...
- John Colvin (4/31) Aug 30 2013 see the first 2 asserts. alias doesn't create a new type, it just
- Maxim Fomin (16/43) Aug 30 2013 Typedef was useful not for poking around new type with same
- Namespace (3/19) Aug 30 2013 Thanks for explanation. I agree that the deprecation of typedef
- H. S. Teoh (6/28) Aug 30 2013 What, scope is deprecated now? When did this happen, and how come I
- Andrei Alexandrescu (9/29) Aug 30 2013 * typedef: it was so ill defined, bringing it any closer to sanity
- H. S. Teoh (21/52) Aug 30 2013 Hmm. Is default values the only use case for typedefs? If so, we can
- Timon Gehr (3/7) Aug 30 2013 I guess it is about the type system not (yet?) being expressive enough
- Maxim Fomin (20/29) Aug 30 2013 I haven't heard about any specific troubles with typedef which
- Andrei Alexandrescu (9/42) Aug 31 2013 The problem is nobody could agree whether typedef was a supertype or a
- Andrej Mitrovic (24/28) Aug 31 2013 So it had to be properly defined in the spec and implemented.
- Jacob Carlborg (4/7) Aug 31 2013 A delegate/function pointer will bypass the protection.
- Andrej Mitrovic (2/3) Aug 31 2013 How will you pass a pointer to a constructor?
- Jacob Carlborg (9/10) Aug 31 2013 No, you invoke the constructor via a pointer.
- Andrej Mitrovic (4/7) Aug 31 2013 Hmm... I hope this can actually work when there are multiple ctors,
- Jacob Carlborg (7/10) Aug 31 2013 Apparently you cannot use "auto" when having an overloaded symbol, so
- Andrej Mitrovic (2/4) Aug 31 2013 Ah, pretty cool workaround.
- Piotr Szturmaj (2/6) Aug 31 2013 Then, why not close that old bug?
- Andrej Mitrovic (2/9) Aug 31 2013 It needs to be fixed first.
- Piotr Szturmaj (2/13) Sep 01 2013 I thought you were discussing about and found a fix.
- Andrei Alexandrescu (6/34) Aug 31 2013 Most of these look approachable, and there are workarounds for the
- Andrej Mitrovic (2/3) Aug 31 2013 Not when you have Kenji around!
- Brian Rogoff (72/74) Aug 31 2013 I'll argue for it and others can then destroy.
- Andrei Alexandrescu (3/16) Aug 31 2013 That use will stay and is useful and uncontested.
- Brian Rogoff (37/40) Aug 31 2013 Sure, but my complaint is that that useful style is cramped by
- Andrei Alexandrescu (4/13) Aug 31 2013 Oh I see. Yes, if we do find a way to define scope to provide
- Jacob Carlborg (68/70) Sep 01 2013 How about this:
- Dicebot (6/11) Sep 01 2013 It is pretty much the meaning I have assumed when collaborating
- Brian Rogoff (8/10) Sep 02 2013 Actually, after a bit more experimentation, I don't object to
- Artur Skawina (18/36) Aug 29 2013 Maybe, no idea what Proxy does.
- Ramon (39/39) Aug 29 2013 Let me share some thoughts and inner warnings, here.
Hello all, Within std.random there are various constructs, such as RandomCover or RandomSample, where it's desirable for the internal state not to be initialized until right before the first call to .front (or one of the other public methods). Some rationale is given here: http://forum.dlang.org/post/mailman.581.1377772931.1719.digitalmars-d puremagic.com http://d.puremagic.com/issues/show_bug.cgi?id=10322 Now, this raises a general question for me. Within code we have two alternative means of error-checking -- assert(), for checking for logical errors in pre-release code, and enforce(), for essential checks that must be enforced even in release code. We have an equivalent to assert() for structs/classes in the form of invariant(), which will make various checks at entry and exit to public functions, but -- if I'm not wrong -- this gets discarded in -release mode. So, is there a case for an equivalent to enforce() -- something that will _always_ be checked on entry/exit to a public method or property? I'd extend that by saying I think it might be a good idea to split that in two, so that one can define entry and exit conditions, but I'm more interested in what everyone thinks of the general idea. It could be very useful for the issues identified with std.random, but I'm not sure how it might impact on things like e.g. function properties. For example, if this enforced entry condition checks for initialization and makes sure initialization takes place of it hasn't already, it would surely destroy the possibility of const for any struct/class method, no? So, I thought I'd throw the idea out there so that others can suggest whether this is potentially useful or whether it's better/safer to hand-code such checks on a function-by-function basis. Thanks & best wishes, -- Joe
Aug 29 2013
On 2013-08-29 13:19, Joseph Rushton Wakeling wrote:So, I thought I'd throw the idea out there so that others can suggest whether this is potentially useful or whether it's better/safer to hand-code such checks on a function-by-function basis.You can quite easily create a wrapper for that. struct EnforceWrapper (T) { T t; auto opDispatch (string name, Args ...) (Args args) { // before code mixin("auto result = " ~ name ~ "(args);"); // after code return result; } } auto obj = EnforceWrapper!(Object)(new Object); obj.toString(); -- /Jacob Carlborg
Aug 29 2013
On 08/29/13 15:26, Jacob Carlborg wrote:On 2013-08-29 13:19, Joseph Rushton Wakeling wrote:Hard-coded unconditional invariants does not seem very useful, and, as Jacob points out, can be done by wrapping the type. That of course creates a new type; if the checks are really supposed to be always-on, then it isn't a problem.So, I thought I'd throw the idea out there so that others can suggest whether this is potentially useful or whether it's better/safer to hand-code such checks on a function-by-function basis.You can quite easily create a wrapper for that. struct EnforceWrapper (T) { T t; auto opDispatch (string name, Args ...) (Args args) { // before code mixin("auto result = " ~ name ~ "(args);"); // after code return result; } } auto obj = EnforceWrapper!(Object)(new Object); obj.toString();In order to handle ref-returns it would have to be more like struct EnforceWrapper(T) { T t; auto ref opDispatch(string M, Args...)(Args args) { {/*before code*/} scope (exit) {/*after code*/} return mixin("t." ~ M ~ "(args)"); } } and need another two overloads for property/field getters and setters. Handling ref-args would add more complexity, but in many cases ignoring them or using auto-ref is enough. artur
Aug 29 2013
On 29/08/13 16:21, Artur Skawina wrote:In order to handle ref-returns it would have to be more like struct EnforceWrapper(T) { T t; auto ref opDispatch(string M, Args...)(Args args) { {/*before code*/} scope (exit) {/*after code*/} return mixin("t." ~ M ~ "(args)"); } } and need another two overloads for property/field getters and setters. Handling ref-args would add more complexity, but in many cases ignoring them or using auto-ref is enough.Interesting. When it comes down to it, it looks like what you're proposing is an extended version of Proxy, no .... ?
Aug 29 2013
On 2013-08-29 16:55, Joseph Rushton Wakeling wrote:Interesting. When it comes down to it, it looks like what you're proposing is an extended version of Proxy, no .... ?It is a proxy. What's the point of a proxy if not to add some additional functionality. -- /Jacob Carlborg
Aug 29 2013
On 29/08/13 21:44, Jacob Carlborg wrote:It is a proxy. What's the point of a proxy if not to add some additional functionality.No, I mean std.typecons.Proxy: The point is that std.typecons.Proxy _just_ wraps the underlying type; it doesn't, so far as I can see, allow you to define extra functionality that must be implemented whenever a public method of the underlying type is called.
Aug 29 2013
On 2013-08-29 23:16, Joseph Rushton Wakeling wrote:No, I mean std.typecons.Proxy: The point is that std.typecons.Proxy _just_ wraps the underlying type; it doesn't, so far as I can see, allow you to define extra functionality that must be implemented whenever a public method of the underlying type is called.Oh, that Proxy. What's the point of it? The example looks like just an "alias this". -- /Jacob Carlborg
Aug 29 2013
On Friday, 30 August 2013 at 06:34:58 UTC, Jacob Carlborg wrote:On 2013-08-29 23:16, Joseph Rushton Wakeling wrote:alias this, but without implicit conversion. It just implements all the op**** functions (including opDispatch).No, I mean std.typecons.Proxy: The point is that std.typecons.Proxy _just_ wraps the underlying type; it doesn't, so far as I can see, allow you to define extra functionality that must be implemented whenever a public method of the underlying type is called.Oh, that Proxy. What's the point of it? The example looks like just an "alias this".
Aug 30 2013
On 2013-08-30 12:56, John Colvin wrote:alias this, but without implicit conversion. It just implements all the op**** functions (including opDispatch).So what's the difference to Typedef, declared just below? -- /Jacob Carlborg
Aug 30 2013
On Friday, 30 August 2013 at 11:50:20 UTC, Jacob Carlborg wrote:On 2013-08-30 12:56, John Colvin wrote:Typedef uses Proxy to do the work. Proxy is a mixing template for adding in to a struct/class and Typedef is a very simple struct making use of it to implement a library typedef. Unfortunately, Typedef is rather lacking as far as being a typedef is concerned, but that's not due to problems with Proxy.alias this, but without implicit conversion. It just implements all the op**** functions (including opDispatch).So what's the difference to Typedef, declared just below?
Aug 30 2013
On 2013-08-30 14:18, John Colvin wrote:Typedef uses Proxy to do the work. Proxy is a mixing template for adding in to a struct/class and Typedef is a very simple struct making use of it to implement a library typedef. Unfortunately, Typedef is rather lacking as far as being a typedef is concerned, but that's not due to problems with Proxy.Ok, I see. -- /Jacob Carlborg
Aug 30 2013
On Friday, 30 August 2013 at 12:18:21 UTC, John Colvin wrote:On Friday, 30 August 2013 at 11:50:20 UTC, Jacob Carlborg wrote:What was the initial reason, to move typedef from the language into the library? I assume, that there is something special about typedef that can not be done with alias. If so, why was it moved? It seems to be a trend, to move incomplete features from the language into the library (See also scope -> scoped). I do not like that. :/On 2013-08-30 12:56, John Colvin wrote:Typedef uses Proxy to do the work. Proxy is a mixing template for adding in to a struct/class and Typedef is a very simple struct making use of it to implement a library typedef. Unfortunately, Typedef is rather lacking as far as being a typedef is concerned, but that's not due to problems with Proxy.alias this, but without implicit conversion. It just implements all the op**** functions (including opDispatch).So what's the difference to Typedef, declared just below?
Aug 30 2013
On Friday, 30 August 2013 at 14:51:40 UTC, Namespace wrote:On Friday, 30 August 2013 at 12:18:21 UTC, John Colvin wrote:I believe typedef was deprecated due to no-one being able to agree on the semantics (although it's a bit before my time). I think it needs to come back as a very simple concept: A type duplication. e.g. typedef int myInt; (or typedef myInt = int;) creates a new type that is exactly identical to int, but is a distinct type in the type system. It should provide *exactly* identical behaviour to e.g. having two structs with identical contents but different names. E.g. struct A{} typedef A tA; alias A aA; alias tA atA; typedef aA taA; assert(!is(tA == A)); assert(is(aA == A)); assert(is(atA == tA)); assert(!is(taA == atA)); etc.... It's a really basic feature that D ought to have.On Friday, 30 August 2013 at 11:50:20 UTC, Jacob Carlborg wrote:What was the initial reason, to move typedef from the language into the library? I assume, that there is something special about typedef that can not be done with alias. If so, why was it moved? It seems to be a trend, to move incomplete features from the language into the library (See also scope -> scoped). I do not like that. :/On 2013-08-30 12:56, John Colvin wrote:Typedef uses Proxy to do the work. Proxy is a mixing template for adding in to a struct/class and Typedef is a very simple struct making use of it to implement a library typedef. Unfortunately, Typedef is rather lacking as far as being a typedef is concerned, but that's not due to problems with Proxy.alias this, but without implicit conversion. It just implements all the op**** functions (including opDispatch).So what's the difference to Typedef, declared just below?
Aug 30 2013
I believe typedef was deprecated due to no-one being able to agree on the semantics (although it's a bit before my time). I think it needs to come back as a very simple concept: A type duplication. e.g. typedef int myInt; (or typedef myInt = int;) creates a new type that is exactly identical to int, but is a distinct type in the type system. It should provide *exactly* identical behaviour to e.g. having two structs with identical contents but different names. E.g. struct A{} typedef A tA; alias A aA; alias tA atA; typedef aA taA; assert(!is(tA == A)); assert(is(aA == A)); assert(is(atA == tA)); assert(!is(taA == atA)); etc.... It's a really basic feature that D ought to have.I don't understand the difference to alias myInt = int; Isn't it the same?
Aug 30 2013
On 30/08/13 17:41, Namespace wrote:I don't understand the difference to alias myInt = int; Isn't it the same?alias means it's a different name for the same type -- typedef should mean it's a different type with the same properties.
Aug 30 2013
On Friday, 30 August 2013 at 15:41:55 UTC, Namespace wrote:see the first 2 asserts. alias doesn't create a new type, it just creates a new identifier for the old type. A rough analogy: alias is by reference and typedef is by valueI believe typedef was deprecated due to no-one being able to agree on the semantics (although it's a bit before my time). I think it needs to come back as a very simple concept: A type duplication. e.g. typedef int myInt; (or typedef myInt = int;) creates a new type that is exactly identical to int, but is a distinct type in the type system. It should provide *exactly* identical behaviour to e.g. having two structs with identical contents but different names. E.g. struct A{} typedef A tA; alias A aA; alias tA atA; typedef aA taA; assert(!is(tA == A)); assert(is(aA == A)); assert(is(atA == tA)); assert(!is(taA == atA)); etc.... It's a really basic feature that D ought to have.I don't understand the difference to alias myInt = int; Isn't it the same?
Aug 30 2013
On Friday, 30 August 2013 at 15:41:55 UTC, Namespace wrote:Typedef was useful not for poking around new type with same properties - new name of existing type, but for non-trivial default value: typedef int myint = 1; void main() { myint my; assert(my is 1); } Alias does not provide this feature, so D hadn't become better with this depreciation (actually the opposite). Nor it had with delete operator depreciation for the replacement of destroy, which like in case with typedef, does not cover full old feature functionality (and functionality what destroy() does provide is useless in many cases). I consider both depreciations as mistakes.I believe typedef was deprecated due to no-one being able to agree on the semantics (although it's a bit before my time). I think it needs to come back as a very simple concept: A type duplication. e.g. typedef int myInt; (or typedef myInt = int;) creates a new type that is exactly identical to int, but is a distinct type in the type system. It should provide *exactly* identical behaviour to e.g. having two structs with identical contents but different names. E.g. struct A{} typedef A tA; alias A aA; alias tA atA; typedef aA taA; assert(!is(tA == A)); assert(is(aA == A)); assert(is(atA == tA)); assert(!is(taA == atA)); etc.... It's a really basic feature that D ought to have.I don't understand the difference to alias myInt = int; Isn't it the same?
Aug 30 2013
Typedef was useful not for poking around new type with same properties - new name of existing type, but for non-trivial default value: typedef int myint = 1; void main() { myint my; assert(my is 1); } Alias does not provide this feature, so D hadn't become better with this depreciation (actually the opposite). Nor it had with delete operator depreciation for the replacement of destroy, which like in case with typedef, does not cover full old feature functionality (and functionality what destroy() does provide is useless in many cases). I consider both depreciations as mistakes.Thanks for explanation. I agree that the deprecation of typedef and delete is/was a mistake, and IMO the deprecation of scope and the library fix scoped is the same mistake.
Aug 30 2013
On Fri, Aug 30, 2013 at 08:20:13PM +0200, Namespace wrote:What, scope is deprecated now? When did this happen, and how come I didn't hear about it? T -- Bare foot: (n.) A device for locating thumb tacks on the floor.Typedef was useful not for poking around new type with same properties - new name of existing type, but for non-trivial default value: typedef int myint = 1; void main() { myint my; assert(my is 1); } Alias does not provide this feature, so D hadn't become better with this depreciation (actually the opposite). Nor it had with delete operator depreciation for the replacement of destroy, which like in case with typedef, does not cover full old feature functionality (and functionality what destroy() does provide is useless in many cases). I consider both depreciations as mistakes.Thanks for explanation. I agree that the deprecation of typedef and delete is/was a mistake, and IMO the deprecation of scope and the library fix scoped is the same mistake.
Aug 30 2013
On 8/30/13 11:20 AM, Namespace wrote:* typedef: it was so ill defined, bringing it any closer to sanity would've broken someone's code. * delete: a festering dung of unsafety straight in the middle of the language. If there's enough argument that the functionality of delete is actually desirable we can always add a function for that. * scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design. AndreiTypedef was useful not for poking around new type with same properties - new name of existing type, but for non-trivial default value: typedef int myint = 1; void main() { myint my; assert(my is 1); } Alias does not provide this feature, so D hadn't become better with this depreciation (actually the opposite). Nor it had with delete operator depreciation for the replacement of destroy, which like in case with typedef, does not cover full old feature functionality (and functionality what destroy() does provide is useless in many cases). I consider both depreciations as mistakes.Thanks for explanation. I agree that the deprecation of typedef and delete is/was a mistake, and IMO the deprecation of scope and the library fix scoped is the same mistake.
Aug 30 2013
On Fri, Aug 30, 2013 at 02:11:32PM -0700, Andrei Alexandrescu wrote:On 8/30/13 11:20 AM, Namespace wrote:Hmm. Is default values the only use case for typedefs? If so, we can already do it without: struct myint { int _impl = 1; alias _impl this; } myint x; assert(x==1); Works on git HEAD.* typedef: it was so ill defined, bringing it any closer to sanity would've broken someone's code.Typedef was useful not for poking around new type with same properties - new name of existing type, but for non-trivial default value: typedef int myint = 1; void main() { myint my; assert(my is 1); } Alias does not provide this feature, so D hadn't become better with this depreciation (actually the opposite). Nor it had with delete operator depreciation for the replacement of destroy, which like in case with typedef, does not cover full old feature functionality (and functionality what destroy() does provide is useless in many cases). I consider both depreciations as mistakes.Thanks for explanation. I agree that the deprecation of typedef and delete is/was a mistake, and IMO the deprecation of scope and the library fix scoped is the same mistake.* delete: a festering dung of unsafety straight in the middle of the language. If there's enough argument that the functionality of delete is actually desirable we can always add a function for that.Well, there's destroy, but last I heard, destroy has some pretty nasty issues on its own... (Not that I'd know anything about it, though, haven't needed to use it. Fortunately.)* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design.[...] What's so terrible about it? And what other solution(s) are there? I only just found out about the library 'scoped' today, and apparently it isn't having a good time either. T -- PNP = Plug 'N' Pray
Aug 30 2013
On 08/30/2013 11:43 PM, H. S. Teoh wrote:I guess it is about the type system not (yet?) being expressive enough to make sure scoped class instances are not escaped.[...] What's so terrible about it?* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design.
Aug 30 2013
On Friday, 30 August 2013 at 21:11:32 UTC, Andrei Alexandrescu wrote:* typedef: it was so ill defined, bringing it any closer to sanity would've broken someone's code.I haven't heard about any specific troubles with typedef which are reason to depreciate the feature. In addition to typedef some other features are also experiencing troubles (shared, ref, properties, invariants,..) yet they are not deprecated.* delete: a festering dung of unsafety straight in the middle of the language.It was useful to delete class objects at the time where programmer knew that he can delete safely to mitigate the problem of dangling references upon class finalization (by invoking dtor when objects are alive). Right now there is no way to do that. By the way, currently dmd accepts putting safe attribute on class dtor definitions which access GC objects - this is a hole in safety (accessing such elements is not a sufficient reason to be hole in safity, but not reseting pointers to null is).If there's enough argument that the functionality of delete is actually desirable we can always add a function for that.Probably yes.* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design. AndreiI cannot remember any feature implemented in phobos that was better then built-in language construct, including scope. Hasn't C++ followed the same policy and at the end it was considered as mistake? At least D has many built-in features comparing to C++ and this is advertized as an advantage.
Aug 30 2013
On 8/30/13 9:55 PM, Maxim Fomin wrote:On Friday, 30 August 2013 at 21:11:32 UTC, Andrei Alexandrescu wrote:The problem is nobody could agree whether typedef was a supertype or a subtype of its original type. It was just a bizarre teratoma grown by happenstance.* typedef: it was so ill defined, bringing it any closer to sanity would've broken someone's code.I haven't heard about any specific troubles with typedef which are reason to depreciate the feature.In addition to typedef some other features are also experiencing troubles (shared, ref, properties, invariants,..) yet they are not deprecated.That's not an argument.That would be a bug.* delete: a festering dung of unsafety straight in the middle of the language.It was useful to delete class objects at the time where programmer knew that he can delete safely to mitigate the problem of dangling references upon class finalization (by invoking dtor when objects are alive). Right now there is no way to do that. By the way, currently dmd accepts putting safe attribute on class dtor definitions which access GC objects - this is a hole in safety (accessing such elements is not a sufficient reason to be hole in safity, but not reseting pointers to null is).Not sure I understand.If there's enough argument that the functionality of delete is actually desirable we can always add a function for that.Probably yes.* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design. AndreiI cannot remember any feature implemented in phobos that was better then built-in language construct, including scope. Hasn't C++ followed the same policy and at the end it was considered as mistake?At least D has many built-in features comparing to C++ and this is advertized as an advantage.I don't think that's how I see things. Andrei
Aug 31 2013
On 8/30/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:* typedef: it was so ill defined, bringing it any closer to sanity would've broken someone's code.So it had to be properly defined in the spec and implemented. Meanwhile we're fighting with the Phobos Typedef and it has way more problems right now, some of which will likely be unsolvable. Bug reports: http://d.puremagic.com/issues/show_bug.cgi?id=10872 http://d.puremagic.com/issues/show_bug.cgi?id=10871 http://d.puremagic.com/issues/show_bug.cgi?id=10778 http://d.puremagic.com/issues/show_bug.cgi?id=8618 http://d.puremagic.com/issues/show_bug.cgi?id=7777 http://d.puremagic.com/issues/show_bug.cgi?id=7737* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design.scoped() has its own quirks, for example: http://d.puremagic.com/issues/show_bug.cgi?id=4636 http://d.puremagic.com/issues/show_bug.cgi?id=5115 http://d.puremagic.com/issues/show_bug.cgi?id=10921 And this last bug that was filed (10921) was a bug that was known since 2010: http://d.puremagic.com/issues/show_bug.cgi?id=5115#c6 So 3 years later, and it's still an issue. I don't even see how Issue 4636 can even be fixed, there's no way for a template in another module to get private access to the class constructor. --- Anyway, we've deprecated old keywords, and introduced half-implemented library replacements. I don't see how we stand any better today than we did before.
Aug 31 2013
On 2013-08-31 11:46, Andrej Mitrovic wrote:So 3 years later, and it's still an issue. I don't even see how Issue 4636 can even be fixed, there's no way for a template in another module to get private access to the class constructor.A delegate/function pointer will bypass the protection. -- /Jacob Carlborg
Aug 31 2013
On 8/31/13, Jacob Carlborg <doob me.com> wrote:A delegate/function pointer will bypass the protection.How will you pass a pointer to a constructor?
Aug 31 2013
On 2013-08-31 14:03, Andrej Mitrovic wrote:How will you pass a pointer to a constructor?No, you invoke the constructor via a pointer. https://github.com/D-Programming-Language/phobos/blob/master/std/conv.d#L4391 Replace that line with: auto dg = &result.__ctor; dg(args); The static-if needs to be adjusted as well. -- /Jacob Carlborg
Aug 31 2013
On 8/31/13, Jacob Carlborg <doob me.com> wrote:Replace that line with: auto dg = &result.__ctor; dg(args);Hmm... I hope this can actually work when there are multiple ctors, how would the compiler know which of the ctors dg should be assigned to?
Aug 31 2013
On 2013-08-31 20:28, Andrej Mitrovic wrote:Hmm... I hope this can actually work when there are multiple ctors, how would the compiler know which of the ctors dg should be assigned to?Apparently you cannot use "auto" when having an overloaded symbol, so just use an explicit type: T delegate (Args) dg = &result.__ctor; dg(args); -- /Jacob Carlborg
Aug 31 2013
On 8/31/13, Jacob Carlborg <doob me.com> wrote:T delegate (Args) dg = &result.__ctor; dg(args);Ah, pretty cool workaround.
Aug 31 2013
On 31.08.2013 21:52, Andrej Mitrovic wrote:On 8/31/13, Jacob Carlborg <doob me.com> wrote:Then, why not close that old bug?T delegate (Args) dg = &result.__ctor; dg(args);Ah, pretty cool workaround.
Aug 31 2013
On 8/31/13, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:On 31.08.2013 21:52, Andrej Mitrovic wrote:It needs to be fixed first.On 8/31/13, Jacob Carlborg <doob me.com> wrote:Then, why not close that old bug?T delegate (Args) dg = &result.__ctor; dg(args);Ah, pretty cool workaround.
Aug 31 2013
On 31.08.2013 22:33, Andrej Mitrovic wrote:On 8/31/13, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:I thought you were discussing about and found a fix.On 31.08.2013 21:52, Andrej Mitrovic wrote:It needs to be fixed first.On 8/31/13, Jacob Carlborg <doob me.com> wrote:Then, why not close that old bug?T delegate (Args) dg = &result.__ctor; dg(args);Ah, pretty cool workaround.
Sep 01 2013
On 8/31/13 2:46 AM, Andrej Mitrovic wrote:On 8/30/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Most of these look approachable, and there are workarounds for the others. Granted, the UDT can't be made 100% like the old typedef (and probably that would be bad, too :o)).* typedef: it was so ill defined, bringing it any closer to sanity would've broken someone's code.So it had to be properly defined in the spec and implemented. Meanwhile we're fighting with the Phobos Typedef and it has way more problems right now, some of which will likely be unsolvable. Bug reports: http://d.puremagic.com/issues/show_bug.cgi?id=10872 http://d.puremagic.com/issues/show_bug.cgi?id=10871 http://d.puremagic.com/issues/show_bug.cgi?id=10778 http://d.puremagic.com/issues/show_bug.cgi?id=8618 http://d.puremagic.com/issues/show_bug.cgi?id=7777 http://d.puremagic.com/issues/show_bug.cgi?id=7737Library issues are a lot easier to deal with than core language issues. Andrei* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design.scoped() has its own quirks, for example: http://d.puremagic.com/issues/show_bug.cgi?id=4636 http://d.puremagic.com/issues/show_bug.cgi?id=5115 http://d.puremagic.com/issues/show_bug.cgi?id=10921 And this last bug that was filed (10921) was a bug that was known since 2010: http://d.puremagic.com/issues/show_bug.cgi?id=5115#c6 So 3 years later, and it's still an issue. I don't even see how Issue 4636 can even be fixed, there's no way for a template in another module to get private access to the class constructor. --- Anyway, we've deprecated old keywords, and introduced half-implemented library replacements. I don't see how we stand any better today than we did before.
Aug 31 2013
On 8/31/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Library issues are a lot easier to deal with than core language issues.Not when you have Kenji around!
Aug 31 2013
On Friday, 30 August 2013 at 21:11:32 UTC, Andrei Alexandrescu wrote:* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design.I'll argue for it and others can then destroy. IME, a lot of the value of functional programming (by which I mean, programming with higher order functions) can be had with downward funargs, as found in Pascal (and more recently, Ada), which don't require garbage collection. The D language expresses closures and higher order functions as delegates, and uses the heap to manage these. I had assumed that we could use 'scope' on the delegate being passed to prevent it's heap allocation, as discussed here: http://stackoverflow.com/questions/4711309/meaning-of-scope-in-d-for-a-parameter I wrote a small test case to try this out, in which I construct a 2-D integration function from a 1-D one, and I use Adam Ruppe's nogc code to seg fault when the GC is hit. Without using a 'scope' on a local variable, I'm forced to pile up the anonymous function calls to get the behavior I want. import std.stdio, std.math; // int delegate(int) adder(int a) { return (int b) { return a + b;}; } float integrate(scope float delegate(float x) f, float lo, float hi, size_t n) { float result = 0.0; float dx = (hi - lo) / n; for (size_t i = 0; i < n; i++) { result += f(lo + i * dx) * dx; } return result; } float integrate(scope float delegate(float, float) f, float x0, float x1, float y0, float y1, size_t nX, size_t nY) { scope auto f_y = delegate float(float y) => integrate(delegate(float x) => f(x,y), x0, x1, nX); return integrate(f_y, y0, y1, nY); // I'll have to write it like this to avoid heap allocation without // local variable scope // return integrate((y) => integrate((x) =>f(x,y), x0, x1, nX), y0, y1, nY); } The code to test demonstrates the issue better, as I'm forced to use inline anonymous functions everywhere to avoid the GC calls (unitCircle and unitSphere omitted for brevity) void main() { scope auto funcX_1 = delegate float(float x) => unitCircle(x); float result1 = integrate(funcX_1 /* (x) => unitCircle(x) */, -1.0, 1.0, 500); writefln("integrate(func1, -1.0, 1.0, 500) = %g", result1); scope auto funcXY_1 = delegate float(float x, float y) => unitSphere(x,y); result1 = integrate(funcXY_1 /* (x,y) => unitSphere(x,y) */, -1.0, 1.0, -1.0, 1.0, 100, 100); writefln("integrate(funcXY_1, -1.0, 1.0, -1.0, 1.0, 100, 100) = %g", result1); } Yes, it's a toy example, but I do program with higher order functions a lot in OCaml and I'd probably use them quite a bit in D, especially if I could avoid impacting the GC. If scope on local variables is going away, it would be nice if the compiler could figure out when I'm using delegate args in a 'downward, non escaping' way and not heap allocate. My tests with DMD indicate that without those 'scope' on the local variable the GC does in fact get hit, and with them it does not. -- Brian PS: I don't really use classes much, so I have little to say about scope on objects PPS: If my missive made little sense, https://en.wikipedia.org/wiki/Funarg_problem http://stackoverflow.com/questions/581182/what-are-downward-funargs
Aug 31 2013
On 8/31/13 1:34 PM, Brian Rogoff wrote:On Friday, 30 August 2013 at 21:11:32 UTC, Andrei Alexandrescu wrote:That use will stay and is useful and uncontested. Andrei* scope: cute and dangerous in equal proportions - great for a movie character, terrible for language design.I'll argue for it and others can then destroy. IME, a lot of the value of functional programming (by which I mean, programming with higher order functions) can be had with downward funargs, as found in Pascal (and more recently, Ada), which don't require garbage collection. The D language expresses closures and higher order functions as delegates, and uses the heap to manage these. I had assumed that we could use 'scope' on the delegate being passed to prevent it's heap allocation, as discussed here: http://stackoverflow.com/questions/4711309/meaning-of-scope-in-d-for-a-parameter
Aug 31 2013
On Saturday, 31 August 2013 at 21:30:40 UTC, Andrei Alexandrescu wrote:Sure, but my complaint is that that useful style is cramped by the inability to have scope on *local variables*. I understand that scope on function parameters will stay. If you're saying that scope on local variables for delegates will stay, then disregard all I've written here, I'm happy! :-). If you look at the code I posted, try removing scope from the 2-D integrate and from the local variable declarations in the main() function, and the program hits the GC, with the scopes, they don't. The problem occurs when I create the local variables to name an anonymous function. I tested this with Adam Ruppe's code which halts when the GC is called. As I said, I'm not arguing for scope on objects, but for contrivances which allow me to program easily with downward funargs and not hit the GC. D goes further than most languages in this and it would be a shame if this capability is removed with no substitute. For those who want to test on their systems, here are the trivial unitCircle and unitSphere I omitted. float unitCircle(float x) { float x2 = x * x; if (x2 < 1.0) { return sqrt(1.0 - x2); } else { return 0.0; } } float unitSphere(float x, float y) { float sum = x*x + y*y; if (sum <= 1.0) { return sqrt(1.0 - sum); } else { return 0.0; } } -- Brianhttp://stackoverflow.com/questions/4711309/meaning-of-scope-in-d-for-a-parameterThat use will stay and is useful and uncontested. Andrei
Aug 31 2013
On 8/31/13 2:57 PM, Brian Rogoff wrote:On Saturday, 31 August 2013 at 21:30:40 UTC, Andrei Alexandrescu wrote:Oh I see. Yes, if we do find a way to define scope to provide guarantees, that would be awesome. AndreiSure, but my complaint is that that useful style is cramped by the inability to have scope on *local variables*.http://stackoverflow.com/questions/4711309/meaning-of-scope-in-d-for-a-parameterThat use will stay and is useful and uncontested. Andrei
Aug 31 2013
On 2013-09-01 01:09, Andrei Alexandrescu wrote:Oh I see. Yes, if we do find a way to define scope to provide guarantees, that would be awesome.How about this: Object bar () { scope a = new Object; return a; } void main () { bar(); } In the above code the compiler can determine that it's unsafe to return "a", with the following error: Error: escaping reference to scope local a So apparently it can do some form of limited escape analysis. But it's quite easy to fool the compiler. The example below won't result in any compiler errors. Object foo (Object o) { return o; } Object bar () { scope a = new Object; return foo(a); } void main () { bar(); } What if we can help the compiler a bit. If we want to pass a scope object to another function it's required that the function takes the parameter as "scope", like this: Object foo (scope Object o) { return o; } Object bar () { scope a = new Object; return foo(a); } void main () { bar(); } Now the compiler knows the "o" in "foo" is scope allocated and will perform the same analysis it did in the first example. This time the error will appear in "foo" and not in "bar". Perhaps we can allow returning scope allocated objects as well if the function is marked as such: scope(Object) foo (scope Object o) { return o; } Object bar () { scope a = new Object; return foo(a); } void main () { bar(); } Now the error will appear again in "bar" since it doesn't return a scope object. -- /Jacob Carlborg
Sep 01 2013
On Sunday, 1 September 2013 at 09:24:46 UTC, Jacob Carlborg wrote:On 2013-09-01 01:09, Andrei Alexandrescu wrote:It is pretty much the meaning I have assumed when collaborating on `scope ref` DIP. Only problem here is, again (and again), attribute inference - using scope variables will require annotating most part of Phobos with `scope` function parameter attributes to be usable.Oh I see. Yes, if we do find a way to define scope to provide guarantees, that would be awesome.How about this: ...
Sep 01 2013
On Saturday, 31 August 2013 at 21:57:37 UTC, Brian Rogoff wrote:On Saturday, 31 August 2013 at 21:30:40 UTC, AndreiActually, after a bit more experimentation, I don't object to removing the scope on local variable delegates. Replacing those with a nested function declaration and a local pointer to function seems to work fine with no GCing, at a very slight cost in elegance IMO; I prefer the delegates to using '&' on a function. It is good to see features being removed from D. -- BrianThat use will stay and is useful and uncontested.
Sep 02 2013
On 08/29/13 16:55, Joseph Rushton Wakeling wrote:On 29/08/13 16:21, Artur Skawina wrote:Maybe, no idea what Proxy does. 'opDispatch' will work for simple cases, and in situations like the one you described, where you just want a bit of sugar for a /local/ always-on invariant, have full control over the wrapped type, and want to eliminate the boilerplate that would otherwise be required. A more generic solution would be something like: struct EnforceWrapper(T) { T t; mixin wrapMembers!t; void _before(string M, A...)() {...} void _after(string M, A...)() {...} } where the 'wrapMembers` mixin-template examines 't' and generates the necessary wrappers. That way overload sets will keep working, etc. arturIn order to handle ref-returns it would have to be more like struct EnforceWrapper(T) { T t; auto ref opDispatch(string M, Args...)(Args args) { {/*before code*/} scope (exit) {/*after code*/} return mixin("t." ~ M ~ "(args)"); } } and need another two overloads for property/field getters and setters. Handling ref-args would add more complexity, but in many cases ignoring them or using auto-ref is enough.Interesting. When it comes down to it, it looks like what you're proposing is an extended version of Proxy, no .... ?
Aug 29 2013
Let me share some thoughts and inner warnings, here. I notice a certain (constructive and pragmatic) tendency here to say "Ha, that can be done" using templates, mixins, whatever. I personally feel that to be somewhat dangerous and short term. It's about concepts. Concepts and a smart and consistent implementation is almost always preferable over a "can be done" hack. DbC is a concept and a powerful one - and the D creators have wisely decided to implement it in D. Unfortunately they seem to not have done it consistently (as some question and threads indicate). There *should* be a clear answer/rule/statement to "which one to use? enforce? invariants? asserts?". And there *should* be a way to let the programmer decide about his use of DbC (as opposed to "release cuts all DbC"). I propose to end the "release cuts out DbC" approach and to instead introduce sth. like " DbC-on" and ' DbC-off'. This, hand in hand with D's smart version mechanism offers much more without losing anything. The current way would be version(release) DbC-off; and being the default D would work as it did before. But we could decide ourselves and we could have DbC available at runtime if we please so. Using DbC-on and DbC-off we could even have good granularity. assert shouldn't be mixed up with DbC (as it often is right now). In fact, I think, assert could/should have two major roles. Ignoring DbC assert has a well established purpose and that's what it has and does in D, too. In relation/context to DbC there is no competition. DbC cares about three scenarios, namely, method entry, method exit and class level ("as long as you are not in a method X is guaranteed to be ..."). assert is no competion but a complement as I see it, in that it offers checks/guarantees for certain single situations that are just not DbC jobs (example: make sure inside a method something doesn't go amok). Thanks for considering A+ -R
Aug 29 2013