Re: partially mutable immutable type problem, crazy idea
On Wednesday, 9 May 2018 at 00:58:51 UTC, jmh530 wrote: On Tuesday, 8 May 2018 at 22:31:10 UTC, Yuxuan Shui wrote: snip] This doesn't compile for me on run.dlang.io: onlineapp.d(22): Error: template onlineapp.f cannot deduce function from argument types !()(B), candidates are: onlineapp.d(1):onlineapp.f(T)(immutable T a) Not supposed to. Was proposing an (crazy) idea here.
Re: partially mutable immutable type problem, crazy idea
On Tuesday, 8 May 2018 at 22:31:10 UTC, Yuxuan Shui wrote: snip] This doesn't compile for me on run.dlang.io: onlineapp.d(22): Error: template onlineapp.f cannot deduce function from argument types !()(B), candidates are: onlineapp.d(1):onlineapp.f(T)(immutable T a)
Re: partially mutable immutable type problem, crazy idea
After watching the DConf 2018 video, I came up with this wild idea: auto f(T)(immutable T a) { // If T is a aggregate type, and I only use (directly // or indirectly) the immutable fields of T, // Then it should be OK to call f() with a partially mutable type return a.x+1; } void main() { struct A { int x; } A a; immutable(A) b; f(a); // <- not fine f(b); // <- fine class B { immutable int x = 10; double f; } auto c = new B; f(c); // <- fine too } I think this should solve the reference counting an immutable object, no? To f(), T will just looks like a normal immutable, uncopyable (because copying means modifying the reference counter) type
Re: sorting a mutable array of immutable objects
On Wednesday, 20 April 2016 at 12:34:28 UTC, Anonymouse wrote: On Wednesday, 20 April 2016 at 10:32:42 UTC, Jeff Thompson wrote: On Wednesday, 20 April 2016 at 09:54:13 UTC, Jeff Thompson wrote: I can create a mutable array of immutable objects, thanks to the answers to my other question https://forum.dlang.org/post/nf57f5$e6v$1...@digitalmars.com . Now I want to sort the array. I found a solution, but I'm not sure it is the best way. Instead of overriding opCmp, class C just defines a static comparison to use with sort (which automatically works with Rebindable). Is there a way to do this where I don't need to specify C.isLess every time I sort? class C { this(int x) immutable { this.x = x; } static bool isLess(const C a, const C b) @safe pure nothrow { return a.x < b.x; } int x; } void main(string[] args) { auto array = new Rebindable!(immutable(C))[2]; array[0] = new immutable C(20); array[1] = new immutable C(10); sort!(C.isLess)(array); } int opCmp(immutable Object o) immutable {} Thanks for a better solution, but I never would have thought to try opCmp without "override" since I assumed that sort was looking for the opCmp defined by Object. So many counter-intuitive mysteries in D. That's why this forum is indipensable.
Re: sorting a mutable array of immutable objects
On Wednesday, 20 April 2016 at 12:34:28 UTC, Anonymouse wrote: On Wednesday, 20 April 2016 at 10:32:42 UTC, Jeff Thompson [...] Also note that sort (std.algorithm.sorting : sort) returns a range and doesn't sort in place. (Lastly this is probably more at home in the Learn forum.) It does sort in place as well apparently, my bad.
Re: sorting a mutable array of immutable objects
On Wednesday, 20 April 2016 at 10:32:42 UTC, Jeff Thompson wrote: On Wednesday, 20 April 2016 at 09:54:13 UTC, Jeff Thompson wrote: I can create a mutable array of immutable objects, thanks to the answers to my other question https://forum.dlang.org/post/nf57f5$e6v$1...@digitalmars.com . Now I want to sort the array. I found a solution, but I'm not sure it is the best way. Instead of overriding opCmp, class C just defines a static comparison to use with sort (which automatically works with Rebindable). Is there a way to do this where I don't need to specify C.isLess every time I sort? class C { this(int x) immutable { this.x = x; } static bool isLess(const C a, const C b) @safe pure nothrow { return a.x < b.x; } int x; } void main(string[] args) { auto array = new Rebindable!(immutable(C))[2]; array[0] = new immutable C(20); array[1] = new immutable C(10); sort!(C.isLess)(array); } int opCmp(immutable Object o) immutable {} That seems to work for me. You want to make it const Object and inout if you want it to work on const and mutable C's as well. Also note that sort (std.algorithm.sorting : sort) returns a range and doesn't sort in place. (Lastly this is probably more at home in the Learn forum.)
Re: sorting a mutable array of immutable objects
On Wednesday, 20 April 2016 at 09:54:13 UTC, Jeff Thompson wrote: I can create a mutable array of immutable objects, thanks to the answers to my other question https://forum.dlang.org/post/nf57f5$e6v$1...@digitalmars.com . Now I want to sort the array. I found a solution, but I'm not sure it is the best way. Instead of overriding opCmp, class C just defines a static comparison to use with sort (which automatically works with Rebindable). Is there a way to do this where I don't need to specify C.isLess every time I sort? class C { this(int x) immutable { this.x = x; } static bool isLess(const C a, const C b) @safe pure nothrow { return a.x < b.x; } int x; } void main(string[] args) { auto array = new Rebindable!(immutable(C))[2]; array[0] = new immutable C(20); array[1] = new immutable C(10); sort!(C.isLess)(array); }
Re: sorting a mutable array of immutable objects
On Wednesday, 20 April 2016 at 09:54:13 UTC, Jeff Thompson wrote: I can create a mutable array of immutable objects, thanks to the answers to my other question https://forum.dlang.org/post/nf57f5$e6v$1...@digitalmars.com . Now I want to sort the array, but the sort function doesn't "see" the opCmp in class C. Do I need to define a custom compare function for each class where I want to use Rebindable? Or can Rebindable itself be updated to "pass through" methods like opCmp? class C { this(int x) immutable { this.x = x; } override int opCmp(Object o) const { return x - (cast(C)o).x; } int x; } void main(string[] args) { auto array = new Rebindable!(immutable(C))[2]; array[0] = new immutable C(20); array[1] = new immutable C(10); sort(array); // Error: "Invalid predicate passed to sort: "a < b"" } Actually, maybe my problem is that the opCmp override should take a const Object (for comparing with an immutable object). Is there a way to do that?
sorting a mutable array of immutable objects
I can create a mutable array of immutable objects, thanks to the answers to my other question https://forum.dlang.org/post/nf57f5$e6v$1...@digitalmars.com . Now I want to sort the array, but the sort function doesn't "see" the opCmp in class C. Do I need to define a custom compare function for each class where I want to use Rebindable? Or can Rebindable itself be updated to "pass through" methods like opCmp? class C { this(int x) immutable { this.x = x; } override int opCmp(Object o) const { return x - (cast(C)o).x; } int x; } void main(string[] args) { auto array = new Rebindable!(immutable(C))[2]; array[0] = new immutable C(20); array[1] = new immutable C(10); sort(array); // Error: "Invalid predicate passed to sort: "a < b"" }
Re: mutable array of immutable objects
On 19.04.2016 14:07, Jeff Thompson wrote: On Tuesday, 19 April 2016 at 11:43:22 UTC, Anonymouse wrote: On Tuesday, 19 April 2016 at 10:41:05 UTC, Jeff Thompson wrote: I want to create a mutable array of immutable objects, but the code below gives the error shown below. It seems that "new immutable(C)[1]" makes the entire array immutable, but it seems I should be able to change the elements of an array of pointers to an object even though the objects are immutable. How to do that? class C { this(int x) immutable { this.x = x; } int x; } void main(string[] args) { auto array = new immutable(C)[1]; array[0] = new immutable C(10); // Error: Cannot modify immutable expression array[0]. } Mind that this is akin to declaring a string (immutable(char)[]) and trying to modify an element. You can append, though. Or rather, make a new array/slice with the new elements concatenated into it. Thanks but then I'm confused as to why the following code is allowed. It is a mutable array of immutable strings. mutable array of mutable strings, actually. immutable(string)[] would be a mutable array of immutable strings. I can modify the array but not the elements they point to. What's so special about a string? string is not a class. It is an alias for immutable(char)[]. Why can't I do that with my own class? ... D has no built-in way to express it. There is https://dlang.org/phobos/std_typecons.html#.Rebindable.
Re: mutable array of immutable objects
Am 19.04.2016 um 12:41 schrieb Jeff Thompson: I want to create a mutable array of immutable objects, but the code below gives the error shown below. It seems that "new immutable(C)[1]" makes the entire array immutable, but it seems I should be able to change the elements of an array of pointers to an object even though the objects are immutable. How to do that? class C { this(int x) immutable { this.x = x; } int x; } void main(string[] args) { auto array = new immutable(C)[1]; array[0] = new immutable C(10); // Error: Cannot modify immutable expression array[0]. } Due to an omission in the type system, this requires the use of the helper type std.typecons.Rebindable: auto array = new Rebindable!(immutable(C))[1]; array[0] = new immutable C(10);
Re: mutable array of immutable objects
On Tuesday, 19 April 2016 at 11:43:22 UTC, Anonymouse wrote: On Tuesday, 19 April 2016 at 10:41:05 UTC, Jeff Thompson wrote: I want to create a mutable array of immutable objects, but the code below gives the error shown below. It seems that "new immutable(C)[1]" makes the entire array immutable, but it seems I should be able to change the elements of an array of pointers to an object even though the objects are immutable. How to do that? class C { this(int x) immutable { this.x = x; } int x; } void main(string[] args) { auto array = new immutable(C)[1]; array[0] = new immutable C(10); // Error: Cannot modify immutable expression array[0]. } Mind that this is akin to declaring a string (immutable(char)[]) and trying to modify an element. You can append, though. Or rather, make a new array/slice with the new elements concatenated into it. Thanks but then I'm confused as to why the following code is allowed. It is a mutable array of immutable strings. I can modify the array but not the elements they point to. What's so special about a string? Why can't I do that with my own class? void main(string[] args) { auto array = new string[1]; array[0] = "a"; }
Re: mutable array of immutable objects
On Tuesday, 19 April 2016 at 10:41:05 UTC, Jeff Thompson wrote: I want to create a mutable array of immutable objects, but the code below gives the error shown below. It seems that "new immutable(C)[1]" makes the entire array immutable, but it seems I should be able to change the elements of an array of pointers to an object even though the objects are immutable. How to do that? class C { this(int x) immutable { this.x = x; } int x; } void main(string[] args) { auto array = new immutable(C)[1]; array[0] = new immutable C(10); // Error: Cannot modify immutable expression array[0]. } Mind that this is akin to declaring a string (immutable(char)[]) and trying to modify an element. You can append, though. Or rather, make a new array/slice with the new elements concatenated into it.
mutable array of immutable objects
I want to create a mutable array of immutable objects, but the code below gives the error shown below. It seems that "new immutable(C)[1]" makes the entire array immutable, but it seems I should be able to change the elements of an array of pointers to an object even though the objects are immutable. How to do that? class C { this(int x) immutable { this.x = x; } int x; } void main(string[] args) { auto array = new immutable(C)[1]; array[0] = new immutable C(10); // Error: Cannot modify immutable expression array[0]. }
Re: @mutable
On 22.02.2016 19:03, Nick Treleaven wrote: On Monday, 22 February 2016 at 17:28:03 UTC, Guillaume Chatelet wrote: static make() { The return type is missing for the make() function: I'm pretty sure static here works just like 'static auto'. In D I think you can use storage classes (and even attributes) to imply auto: const foo(){return 5;} assert(foo() == 5); It does not really "imply auto". 'auto' means nothing in this context, it's just a crutch for the parser. The return type is deduced if it is left out. In order to leave it out, you need to provide some storage class. 'auto' is just one possibility.
Re: @mutable
On Monday, 22 February 2016 at 18:03:03 UTC, Nick Treleaven wrote: On Monday, 22 February 2016 at 17:28:03 UTC, Guillaume Chatelet wrote: static make() { The return type is missing for the make() function: I'm pretty sure static here works just like 'static auto'. In D I think you can use storage classes (and even attributes) to imply auto: const foo(){return 5;} assert(foo() == 5); Ha right indeed it's probably going to work. It was just a bit surprising.
Re: @mutable
On Monday, 22 February 2016 at 17:28:03 UTC, Guillaume Chatelet wrote: static make() { The return type is missing for the make() function: I'm pretty sure static here works just like 'static auto'. In D I think you can use storage classes (and even attributes) to imply auto: const foo(){return 5;} assert(foo() == 5);
Re: @mutable
static make() { The return type is missing for the make() function:
Re: @mutable
On Sunday, 21 February 2016 at 15:03:39 UTC, Marc Schütz wrote: I've adapted my previous DIP on lazy initialization to make it usable for logical immutability, as is useful for reference counting, among other things: http://wiki.dlang.org/DIP89 From the DIP: The second rule (@system) prevents accidental accesses that violate [logical const-ness] It seems we could use @mutable as a method attribute instead of @trusted const. The advantage would be that code is still checked for @safety. Requiring it still helps to prevent unintentional mutation and remind the programmer about correct logical const encapsulation. I realise @trusted has more impact but really here this use isn't related to memory safety, (or is it)?
Re: @mutable
On Sunday, 21 February 2016 at 18:19:35 UTC, Nick Treleaven wrote: BTW the Usage section still uses lazy. I think the RCObject code shouldn't use new to construct the struct here: auto o = new immutable(RCObject); It probably needs to be on the stack instead. Thanks, fixed. (I also made a minor edit for formatting/readability, hope that's OK). Sure :-)
Re: @mutable
On Sunday, 21 February 2016 at 15:03:39 UTC, Marc Schütz wrote: I've adapted my previous DIP on lazy initialization to make it usable for logical immutability, as is useful for reference counting, among other things: http://wiki.dlang.org/DIP89 BTW the Usage section still uses lazy. I think the RCObject code shouldn't use new to construct the struct here: auto o = new immutable(RCObject); It probably needs to be on the stack instead. (I also made a minor edit for formatting/readability, hope that's OK).
@mutable
I've adapted my previous DIP on lazy initialization to make it usable for logical immutability, as is useful for reference counting, among other things: http://wiki.dlang.org/DIP89
Re: [idea] Mutable pointee/ RCString
On Sunday, 7 February 2016 at 14:00:24 UTC, Iakh wrote: Explanations: As far as "immutable" transitive: -- immutable RCString str; *str.counter++; // Impossible/error/undefined behavior(with const cast) -- Language defines immutable to do some optimizations based on true constness of str, fields, and variables pointed by fields. But if pointer would be treated by optimizer(not by GC) as void* (or size_t) pointee "true constness" does not matter. The only drawback is the immutable function that reads @mutable field can't be @pure because it reads "global variable".
[idea] Mutable pointee/ RCString
Is it hard to make pointee data mutable? E.g. if have: -- struct RCString { private char[] data; private @mutable int* counter; } -- So for optimiser (in case of immutable) this looks like -- struct RCString { private char[] data; private @mutable void* counter; // pointer to garbage } --
Re: implicit conversion to mutable via alias this
On Saturday 21 June 2014 21:55, wrote: > I can only guess Kenji's reasons, but I believe it's related to > DIP49, which he created: > > http://wiki.dlang.org/DIP49 Thanks a bunch. That sheds quite some light on it.
Re: implicit conversion to mutable via alias this
I can only guess Kenji's reasons, but I believe it's related to DIP49, which he created: http://wiki.dlang.org/DIP49 The DIP describes how copying between differently qualified types should work. I guess his stance is that this should always go via the postblit, probably to avoid uncertainties about postblit or alias this has priority over the other. IMO this makes sense. (And you're right, this is currently not implemented.)
Re: implicit conversion to mutable via alias this
I'd still appreciate feedback on this.
Re: implicit conversion to mutable via alias this
bump
Re: implicit conversion to mutable via alias this
Anyone?
implicit conversion to mutable via alias this
Last week I filed issues 12883 [1] and 12884 [2], and made dmd pull request #3654 [3] to fix them. The changes would make it possible to use alias this for implicit conversion to mutable when the conversion is otherwise not possible. Issue 12883 is about structs. dmd's current rules for conversion of structs are essentially: 1) If the unqualified source and target types match, and the members can be converted, do that. 2) Otherwise, if the unqualified types do not match, try alias this. 3) Otherwise, fail. I'd like to change step 2 to 2) Otherwise, try alias this. That is, in particular, if the unqualified types match but the members can't be converted, try alias this. Kenji rejected the pull request saying that conversion to mutable should be handled by postblit. As far as I can see, that doesn't work right now. And I don't see how it's supposed to work. We can't allow conversion to mutable just because there's a postblit. And there is no way to mark/overload the postblit for a const-stripping conversion, is there? Kenji, could you elaborate on how postblit is supposed to take care of this? Or maybe someone else has some insight? Or maybe you think that PR #3654 is totally awesome and should be pulled? ;) As for classes (issue 12884), dmd already accepts alias this to mutable here. But one way or the other it's buggy. The motivation for all this came from issue 12885 [4]: There is a hack in place in dmd to allow implicit conversion of const(Rebindable!(const Object)) to mutable. In my opinion it's too permissive and lets code be accepted that should be rejected. With to- mutable-via-alias-this the conversion could be implemented in Rebindable itself and the hack could be reverted. [1] https://issues.dlang.org/show_bug.cgi?id=12883 [2] https://issues.dlang.org/show_bug.cgi?id=12884 [3] https://github.com/D-Programming-Language/dmd/pull/3654 [4] https://issues.dlang.org/show_bug.cgi?id=12885
Re: How do you copy a const struct to a mutable?
Malte Skarupke: What am I missing in order to do this? In D when you define a struct inside a function, it's not a POD any more. If you define it as "static struct A" instead of "struct A", your code will compile. Unfortunately DMD gives a too much generic error message in this case, it doesn't explain what's the problem: test.d(7): Error: cannot implicitly convert expression (a) of type const(A) to A Bye, bearophile
How do you copy a const struct to a mutable?
I want to get this to compile: void main() { struct A { this(int x) { this.x = x; } int x; } const(A) a = A(5); A b = a; } It should clearly be legal to create a non-const copy of the struct. What am I missing in order to do this? Cheers, Malte
Re: How mutable is immutable?
On 18/10/12 19:43, Timon Gehr wrote: On 10/18/2012 10:08 AM, Don Clugston wrote: On 17/10/12 18:02, Timon Gehr wrote: On 10/17/2012 01:49 PM, Don Clugston wrote: ... That's the point -- *which* checks are missing from @safe? Escaping stack data and arbitrarily freeing memory are not operations found in memory safe languages. HOW do you propose to check for escaping stack data? Static escape analysis. Use the 'scope' qualifier to designate data that is not allowed to be escaped in order to make it modular. ... The implementation of the 'scope' storage class should be fixed. We could then require an unsafe cast(scope) to disable prevention of stack address escaping. No we can't. f cannot know that the string it has been given is on the stack. So main() must prevent it from being given to f() in the first place. How can it do that? f can know that it mustn't escape it, which is enough. void foo(bool b, string y) { immutable (char)[4] x = "abba"; string s = b ? x : y; f(s); } Make it safe. It is safe if the parameter to f is marked with 'scope'. (and this in turn obliges f not to escape it.) Well, OK, but that involves changing the semantics of immutable. You could not pass this kind of "local immutable" to _any_ existing code. It would render almost all existing code that uses immutable obsolete. And what do you get in exchange? Practically nothing! Analyze scope on the expression level. The analysis would determine that x[] is 'scope'. It would conservatively propagate this fact to (b ? x[] : y). Then the local variable 's' will get the 'scope' storage class. In general, use a fixed-point iteration to determine all local variables that might refer to scope'd data and prevent that they get escaped. Rust's borrowed pointers may give some hints on how to extend 'scope' to fields of structs. I think it is more fundamental than that. As to delete, delete is as unsafe when the involved data is immutable as when it is mutable. Why require an additional cast in one case? This is not about safety. Modifying immutable data breaks the type system. Deleting mutable data does not. AFAIK it is safe to implement delete as a call to the finalizer, followed by setting the memory to T.init. ... Now I see where you are coming from. This is indeed a safe approach for references to/arrays of fully mutable value types, but not for delete in general. Make sure to treat void* specially though. struct S{ immutable int x; this(int x){this.x=x;}} void main()@safe{ void* s = new S(2); delete s; } Class instance memory does not have a T.init, because it is not assigned a T. And even if it was, how would you know at compile time if the bound instance has any immutable fields? Should that be a runtime exception? Probably. Yeah, it's a bit hard if you have a base class, you can't statically check if it has immutable members in a derived class. Or you could be conservative and disallow delete of anything where you don't know the exact type at compile time.
Re: How mutable is immutable?
On 10/18/2012 10:08 AM, Don Clugston wrote: On 17/10/12 18:02, Timon Gehr wrote: On 10/17/2012 01:49 PM, Don Clugston wrote: ... That's the point -- *which* checks are missing from @safe? Escaping stack data and arbitrarily freeing memory are not operations found in memory safe languages. HOW do you propose to check for escaping stack data? Static escape analysis. Use the 'scope' qualifier to designate data that is not allowed to be escaped in order to make it modular. ... The implementation of the 'scope' storage class should be fixed. We could then require an unsafe cast(scope) to disable prevention of stack address escaping. No we can't. f cannot know that the string it has been given is on the stack. So main() must prevent it from being given to f() in the first place. How can it do that? f can know that it mustn't escape it, which is enough. void foo(bool b, string y) { immutable (char)[4] x = "abba"; string s = b ? x : y; f(s); } Make it safe. It is safe if the parameter to f is marked with 'scope'. (and this in turn obliges f not to escape it.) Analyze scope on the expression level. The analysis would determine that x[] is 'scope'. It would conservatively propagate this fact to (b ? x[] : y). Then the local variable 's' will get the 'scope' storage class. In general, use a fixed-point iteration to determine all local variables that might refer to scope'd data and prevent that they get escaped. Rust's borrowed pointers may give some hints on how to extend 'scope' to fields of structs. I think it is more fundamental than that. As to delete, delete is as unsafe when the involved data is immutable as when it is mutable. Why require an additional cast in one case? This is not about safety. Modifying immutable data breaks the type system. Deleting mutable data does not. AFAIK it is safe to implement delete as a call to the finalizer, followed by setting the memory to T.init. ... Now I see where you are coming from. This is indeed a safe approach for references to/arrays of fully mutable value types, but not for delete in general. Make sure to treat void* specially though. struct S{ immutable int x; this(int x){this.x=x;}} void main()@safe{ void* s = new S(2); delete s; } Class instance memory does not have a T.init, because it is not assigned a T. And even if it was, how would you know at compile time if the bound instance has any immutable fields? Should that be a runtime exception?
Re: How mutable is immutable?
On 10/18/12 10:08, Don Clugston wrote: > On 17/10/12 18:02, Timon Gehr wrote: >> On 10/17/2012 01:49 PM, Don Clugston wrote: >>> On 01/01/12 13:50, Timon Gehr wrote: >>>> On 01/01/2012 10:40 AM, Denis Shelomovskij wrote: >>>>> So, I'm a function `f`, I have an `immutable(type)[]` argument and I >>>>> want to store it for my friend `g` in an TLS variable `v`: >>>>> --- >>>>> string v; >>>>> debug string sure; >>>>> >>>>> void f(string s) { v = s; debug sure = s.idup; } >>>>> void g() { assert(v == sure); } >>>>> --- >>>>> I also store a copy of `s` into `sure` for my friend to ensure >>>>> immutable >>>>> date hasn't been mutated. >>>>> Can my friend's assertion ever fail without breaking a type-system? >>>>> Sure. Just consider this: >>>>> --- >>>>> void main() { >>>>> auto s = "abba".idup; >>>>> f(s); >>>>> delete s; >>>>> g(); >>>>> } >>>>> --- >>>>> Is it by-design? Looks like deleting immutable (and const because of >>>>> implicit conversion) data should be prohibited. >>>>> OK. Let `delete` be fixed. Can we still fail? >>>>> --- >>>>> void h() { >>>>> immutable(char)[4] s = "abba"; >>>>> f(s); >>>>> } >>>>> void main() { >>>>> h(); >>>>> g(); >>>>> } >>>>> --- >>>>> Damn! So, what can we do with it? Not sure, but I have a proposal. >>>>> >>>>> Fix it in language: >>>>> * disallow `delete` of const/immutable data >>>>> * disallow immutable data on the stack >>>>> >>>>> This makes data really immutable if I don't miss something. Anyway, I >>>>> want `immutable` qualified data to be immutable without breaking a >>>>> type-system (if one do it, its his own responsibility), so some changes >>>>> should be made (IMHO). >>>> >>>> You are using unsafe language features to break the type system. That is >>>> not the fault of the type system. >>>> >>>> '@safe:' at the top of the program should stop both examples from >>>> working, it is a bug that it does not. >>> >>> That's the point -- *which* checks are missing from @safe? >> >> Escaping stack data and arbitrarily freeing memory are not operations >> found in memory safe languages. > > HOW do you propose to check for escaping stack data? /How/ is not a problem (ignoring implementation costs), the /language definition/ part is trickier - you need a very precise definition of what is allowed and what isn't; otherwise different compilers will make different decisions and every compiler will support only a vendor-specific non-std dialect... (eg storing a scoped-ref into some kind of container, passing that down to other functions could work, but what if you then need to let the container escape and want to do that by removing the scoped-ref? It might be possible for the compiler to prove that it's safe, but it's unlikely that every compiler will act the same) >>> But I'm not sure that you're right, this looks broken to me, even >>> without @safe. >>> >>> What does it mean to create immutable data on the stack? The stack is >>> intrinsically mutable! >> >> So is the heap. > > No it is not. Data on the stack *cannot* survive past the end of the function > call. Data on the heap can last forever. Lifetime and mutability are different things. >> What does it mean to garbage collect immutable data? > > From the point of view of the application, it doesn't happen. There are no > observable semantics. It's merely an implementation detail. > >> What does it mean to allocate an 'int' on the stack? >> >>> What does it mean to delete immutable data? >> >> Deallocate the storage for it and make it available for reuse. >> Accessing it afterwards leads to arbitrary behaviour. This is the same >> with mutable data. As the program may behave arbitrarily in this case, >> it is valid behaviour to act as if immutable data changed. > > No, you've broken the type system if you've deleted immutable data. > If I have a reference to an immutable variable, I have a guarantee that it > w
Re: How mutable is immutable?
On 17/10/12 18:02, Timon Gehr wrote: On 10/17/2012 01:49 PM, Don Clugston wrote: On 01/01/12 13:50, Timon Gehr wrote: On 01/01/2012 10:40 AM, Denis Shelomovskij wrote: So, I'm a function `f`, I have an `immutable(type)[]` argument and I want to store it for my friend `g` in an TLS variable `v`: --- string v; debug string sure; void f(string s) { v = s; debug sure = s.idup; } void g() { assert(v == sure); } --- I also store a copy of `s` into `sure` for my friend to ensure immutable date hasn't been mutated. Can my friend's assertion ever fail without breaking a type-system? Sure. Just consider this: --- void main() { auto s = "abba".idup; f(s); delete s; g(); } --- Is it by-design? Looks like deleting immutable (and const because of implicit conversion) data should be prohibited. OK. Let `delete` be fixed. Can we still fail? --- void h() { immutable(char)[4] s = "abba"; f(s); } void main() { h(); g(); } --- Damn! So, what can we do with it? Not sure, but I have a proposal. Fix it in language: * disallow `delete` of const/immutable data * disallow immutable data on the stack This makes data really immutable if I don't miss something. Anyway, I want `immutable` qualified data to be immutable without breaking a type-system (if one do it, its his own responsibility), so some changes should be made (IMHO). You are using unsafe language features to break the type system. That is not the fault of the type system. '@safe:' at the top of the program should stop both examples from working, it is a bug that it does not. That's the point -- *which* checks are missing from @safe? Escaping stack data and arbitrarily freeing memory are not operations found in memory safe languages. HOW do you propose to check for escaping stack data? But I'm not sure that you're right, this looks broken to me, even without @safe. What does it mean to create immutable data on the stack? The stack is intrinsically mutable! So is the heap. No it is not. Data on the stack *cannot* survive past the end of the function call. Data on the heap can last forever. What does it mean to garbage collect immutable data? From the point of view of the application, it doesn't happen. There are no observable semantics. It's merely an implementation detail. What does it mean to allocate an 'int' on the stack? What does it mean to delete immutable data? Deallocate the storage for it and make it available for reuse. Accessing it afterwards leads to arbitrary behaviour. This is the same with mutable data. As the program may behave arbitrarily in this case, it is valid behaviour to act as if immutable data changed. No, you've broken the type system if you've deleted immutable data. If I have a reference to an immutable variable, I have a guarantee that it will never change. delete will break that guarantee. With a mutable variable, I have no such guarantee. (It's not safe to allocate something different in the deleted location, but it's OK to run the finalizer and then wipe all the memory). I think it's reasonable for both of them to require a cast, even in @system code. The implementation of the 'scope' storage class should be fixed. We could then require an unsafe cast(scope) to disable prevention of stack address escaping. No we can't. f cannot know that the string it has been given is on the stack. So main() must prevent it from being given to f() in the first place. How can it do that? void foo(bool b, string y) { immutable (char)[4] x = "abba"; string s = b ? x : y; f(s); } Make it safe. Rust's borrowed pointers may give some hints on how to extend 'scope' to fields of structs. I think it is more fundamental than that. As to delete, delete is as unsafe when the involved data is immutable as when it is mutable. Why require an additional cast in one case? This is not about safety. Modifying immutable data breaks the type system. Deleting mutable data does not. AFAIK it is safe to implement delete as a call to the finalizer, followed by setting the memory to T.init. Only the GC can determine if it is safe to reuse the memory. Deleting immutable data just doesn't make sense.
Re: How mutable is immutable?
The issue is that you're thinking as you would in Java. I guess the rule in D for immutable is this: Immutable data won't change as long as it exists. The last part of that sentence would be a stupid thing to say in Java because things don't just cease to exist while you're still doing something with them. That is not the case in D. That being said it's very unlikely that you will ever run into this situation. You have to end the lifetime of the object manually to run into these issues. And in that case it'll be very easy to figure out what's wrong.
Re: How mutable is immutable?
On 10/17/2012 01:49 PM, Don Clugston wrote: On 01/01/12 13:50, Timon Gehr wrote: On 01/01/2012 10:40 AM, Denis Shelomovskij wrote: So, I'm a function `f`, I have an `immutable(type)[]` argument and I want to store it for my friend `g` in an TLS variable `v`: --- string v; debug string sure; void f(string s) { v = s; debug sure = s.idup; } void g() { assert(v == sure); } --- I also store a copy of `s` into `sure` for my friend to ensure immutable date hasn't been mutated. Can my friend's assertion ever fail without breaking a type-system? Sure. Just consider this: --- void main() { auto s = "abba".idup; f(s); delete s; g(); } --- Is it by-design? Looks like deleting immutable (and const because of implicit conversion) data should be prohibited. OK. Let `delete` be fixed. Can we still fail? --- void h() { immutable(char)[4] s = "abba"; f(s); } void main() { h(); g(); } --- Damn! So, what can we do with it? Not sure, but I have a proposal. Fix it in language: * disallow `delete` of const/immutable data * disallow immutable data on the stack This makes data really immutable if I don't miss something. Anyway, I want `immutable` qualified data to be immutable without breaking a type-system (if one do it, its his own responsibility), so some changes should be made (IMHO). You are using unsafe language features to break the type system. That is not the fault of the type system. '@safe:' at the top of the program should stop both examples from working, it is a bug that it does not. That's the point -- *which* checks are missing from @safe? Escaping stack data and arbitrarily freeing memory are not operations found in memory safe languages. But I'm not sure that you're right, this looks broken to me, even without @safe. What does it mean to create immutable data on the stack? The stack is intrinsically mutable! So is the heap. What does it mean to garbage collect immutable data? What does it mean to allocate an 'int' on the stack? What does it mean to delete immutable data? Deallocate the storage for it and make it available for reuse. Accessing it afterwards leads to arbitrary behaviour. This is the same with mutable data. As the program may behave arbitrarily in this case, it is valid behaviour to act as if immutable data changed. I think it's reasonable for both of them to require a cast, even in @system code. The implementation of the 'scope' storage class should be fixed. We could then require an unsafe cast(scope) to disable prevention of stack address escaping. Rust's borrowed pointers may give some hints on how to extend 'scope' to fields of structs. As to delete, delete is as unsafe when the involved data is immutable as when it is mutable. Why require an additional cast in one case?
Re: How mutable is immutable?
On 01/01/12 13:50, Timon Gehr wrote: On 01/01/2012 10:40 AM, Denis Shelomovskij wrote: So, I'm a function `f`, I have an `immutable(type)[]` argument and I want to store it for my friend `g` in an TLS variable `v`: --- string v; debug string sure; void f(string s) { v = s; debug sure = s.idup; } void g() { assert(v == sure); } --- I also store a copy of `s` into `sure` for my friend to ensure immutable date hasn't been mutated. Can my friend's assertion ever fail without breaking a type-system? Sure. Just consider this: --- void main() { auto s = "abba".idup; f(s); delete s; g(); } --- Is it by-design? Looks like deleting immutable (and const because of implicit conversion) data should be prohibited. OK. Let `delete` be fixed. Can we still fail? --- void h() { immutable(char)[4] s = "abba"; f(s); } void main() { h(); g(); } --- Damn! So, what can we do with it? Not sure, but I have a proposal. Fix it in language: * disallow `delete` of const/immutable data * disallow immutable data on the stack This makes data really immutable if I don't miss something. Anyway, I want `immutable` qualified data to be immutable without breaking a type-system (if one do it, its his own responsibility), so some changes should be made (IMHO). You are using unsafe language features to break the type system. That is not the fault of the type system. '@safe:' at the top of the program should stop both examples from working, it is a bug that it does not. That's the point -- *which* checks are missing from @safe? But I'm not sure that you're right, this looks broken to me, even without @safe. What does it mean to create immutable data on the stack? The stack is intrinsically mutable! What does it mean to delete immutable data? I think it's reasonable for both of them to require a cast, even in @system code.
Re: mutable reference > pointer
On Wednesday, 6 June 2012 at 11:45:34 UTC, Gor Gyolchanyan wrote: I had this idea for a long time now and was trying to find a reason why it was a bad idea. I failed to find that reason, so here it is: The idea is to have a mutable reference: int& a; // This is a mutable reference (essentially a pointer, but with reversed behavior). assert(&a is null); // the address must be taken before address-related operations can be performed a = 20; // Access violation error due to null pointer dereferencing. &a = new int; // Addresses, taken from mutable references are lvalues. a = 20; assert(a == 20); &c = null; assert(&c is null); The idea here is to further reduce the need to explicitly deal with addresses, while providing the number one reason why people use pointers: indirection. This mechanism will exclude indirection from the list of reasons why one would use pointers. This is also good for reducing compiler magic, when dealing with ref parameters and return types for functions. This mutable reference would be the complete compliment of pointers: dereferencing a pointer yields a mutable reference, taking address of a mutable reference yields a mutable pointer. This is not a proposition to add to D, but rather an idea, which could eventually end up in D if you guys think it's worth it. It could also be used to remove the magic from reference types, by adding their non-reference counter-parts and have their "constructors" return such a mutable reference. Here's a consideration: when I was a beginner learning C++ the difference between reference and pointer types (and their operators) confused me so much I avoided learning what pointers were for a long time: type create from t T* ptr = &t T& ref = t
Re: mutable reference > pointer
On Wednesday, 6 June 2012 at 11:58:12 UTC, Dmitry Olshansky wrote: On 06.06.2012 15:45, Gor Gyolchanyan wrote: I had this idea for a long time now and was trying to find a reason why it was a bad idea. I failed to find that reason, so here it is: There is. For one thing I like pointer for being explicit about dereferencing something. In this sense having ref arguments of function is IMO step backwards: mutator(a, b); vs mutator(a, &b); which one more likely to mutate arguments? In today's D you'll never know. I never had any issue with this in the Pascal language family. You need anyway always to look the function code, as you cannot know what other side-effects might also be affected by the function call. Plus any modern IDE can show the definition as tooltip. -- Paulo
Re: mutable reference > pointer
On Wed, Jun 6, 2012 at 3:58 PM, Dmitry Olshansky wrote: > On 06.06.2012 15:45, Gor Gyolchanyan wrote: >> >> I had this idea for a long time now and was trying to find a reason >> why it was a bad idea. >> I failed to find that reason, so here it is: >> > > There is. For one thing I like pointer for being explicit about > dereferencing something. In this sense having ref arguments of function is > IMO step backwards: > mutator(a, b); > vs > mutator(a, &b); > > which one more likely to mutate arguments? > In today's D you'll never know. > > >> The idea is to have a mutable reference: >> >> int& a; // This is a mutable reference (essentially a pointer, but >> with reversed behavior). >> assert(&a is null); // the address must be taken before >> address-related operations can be performed >> a = 20; // Access violation error due to null pointer dereferencing. >> &a = new int; // Addresses, taken from mutable references are lvalues. >> a = 20; >> assert(a == 20); >> &c = null; >> assert(&c is null); >> >> The idea here is to further reduce the need to explicitly deal with >> addresses, while providing the number one reason why people use >> pointers: indirection. >> This mechanism will exclude indirection from the list of reasons why >> one would use pointers. >> This is also good for reducing compiler magic, when dealing with ref >> parameters and return types for functions. >> This mutable reference would be the complete compliment of pointers: >> dereferencing a pointer yields a mutable reference, taking address of >> a mutable reference yields a mutable pointer. >> >> This is not a proposition to add to D, but rather an idea, which could >> eventually end up in D if you guys think it's worth it. >> It could also be used to remove the magic from reference types, by >> adding their non-reference counter-parts and have their "constructors" >> return such a mutable reference. >> > > > -- > Dmitry Olshansky This is completely dependent on the logic of your code, including the data type in question. Explicit knowledge of mutability is not necessary only for value types. Reference types are inherently mutable. This reference idea just produces a reference version of a given type. If you're concerned about the mutability - use pointers. This is not a replacement of pointers, but a complement for them. -- Bye, Gor Gyolchanyan.
Re: mutable reference > pointer
On 06.06.2012 15:45, Gor Gyolchanyan wrote: I had this idea for a long time now and was trying to find a reason why it was a bad idea. I failed to find that reason, so here it is: There is. For one thing I like pointer for being explicit about dereferencing something. In this sense having ref arguments of function is IMO step backwards: mutator(a, b); vs mutator(a, &b); which one more likely to mutate arguments? In today's D you'll never know. The idea is to have a mutable reference: int& a; // This is a mutable reference (essentially a pointer, but with reversed behavior). assert(&a is null); // the address must be taken before address-related operations can be performed a = 20; // Access violation error due to null pointer dereferencing. &a = new int; // Addresses, taken from mutable references are lvalues. a = 20; assert(a == 20); &c = null; assert(&c is null); The idea here is to further reduce the need to explicitly deal with addresses, while providing the number one reason why people use pointers: indirection. This mechanism will exclude indirection from the list of reasons why one would use pointers. This is also good for reducing compiler magic, when dealing with ref parameters and return types for functions. This mutable reference would be the complete compliment of pointers: dereferencing a pointer yields a mutable reference, taking address of a mutable reference yields a mutable pointer. This is not a proposition to add to D, but rather an idea, which could eventually end up in D if you guys think it's worth it. It could also be used to remove the magic from reference types, by adding their non-reference counter-parts and have their "constructors" return such a mutable reference. -- Dmitry Olshansky
mutable reference > pointer
I had this idea for a long time now and was trying to find a reason why it was a bad idea. I failed to find that reason, so here it is: The idea is to have a mutable reference: int& a; // This is a mutable reference (essentially a pointer, but with reversed behavior). assert(&a is null); // the address must be taken before address-related operations can be performed a = 20; // Access violation error due to null pointer dereferencing. &a = new int; // Addresses, taken from mutable references are lvalues. a = 20; assert(a == 20); &c = null; assert(&c is null); The idea here is to further reduce the need to explicitly deal with addresses, while providing the number one reason why people use pointers: indirection. This mechanism will exclude indirection from the list of reasons why one would use pointers. This is also good for reducing compiler magic, when dealing with ref parameters and return types for functions. This mutable reference would be the complete compliment of pointers: dereferencing a pointer yields a mutable reference, taking address of a mutable reference yields a mutable pointer. This is not a proposition to add to D, but rather an idea, which could eventually end up in D if you guys think it's worth it. It could also be used to remove the magic from reference types, by adding their non-reference counter-parts and have their "constructors" return such a mutable reference. -- Bye, Gor Gyolchanyan.
Re: Add compile time mutable variable type
On Tuesday, 5 June 2012 at 05:39:34 UTC, Ali Çehreli wrote: On 06/04/2012 06:22 PM, Chang Long wrote: > The previous two example is not correct, please see this one: Your post sounds interesting but there are lots of errors: > size_t line l; <-- ERROR > void this(string name) { <-- ERROR etc. Can you actually compile that code? It would be better if you can present your question with less code. Ali this is what I mean, I can't make it more smaller. --- abstract class Template_parameter_Base{ TypeInto ti; string name ; this(TypeInto ti, string name) { this.ti = ti ; this.name = name ; } } class Template_parameter(T) : Template_parameter_Base { T value ; alias value this; void assign(ref T t){ value = t ; } } class Template_Engine { string name ; Template_parameter_Base[string] parameters ; void this(string name) { this.name = name ; } } class Template(string name) { static compile_time_mutable(Template_Engine) engine = new Template_Engine!name ; void assign(string name, T)(ref T t){ static if(name in vars) { static const parameter = cast(Template_parameter!T) engine.parameters[name]; static assert( parameter.ti == typeid(T) ); } else { static const parameter = new Template_parameter!T(typeid(T), name) ; static engine.parameters[name] = parameter ; } parameter.assign(t); } } void main(){ static tpl = new Template!"home_page" ; auto is_login = false ; tpl.assign!"is_login"( is_login) ) ; if( is_login ) { tpl.assign!"user"( new User() ) ; } auto string switch_user = "new_user_email" ; if( switch_user !is null ) { tpl.assign!"user"( new User(switch_user) ) ; } tpl.assign!"user"( true ) ; // static assert error } --- After think what is done, a better way is put the Template_parameter on the annotation data section. some things like this: class Template_Engine(string name) { static this_ti = typeid( typeof(this) ) ; void assign(string name, T)(ref T t){ static const parameter = new Template_parameter!(T, name) ; ti.createAnnotation("Template_Engine_Parameter", parameter); parameter.assign(t); } void render(){ auto parameters = this_ti.getParametersByName("Template_Engine_Parameter") ; // compile template to dynamic link library by template file and parameters } }
Re: Add compile time mutable variable type
On 06/04/2012 06:22 PM, Chang Long wrote: > The previous two example is not correct, please see this one: Your post sounds interesting but there are lots of errors: > size_t line l; <-- ERROR > void this(string name) { <-- ERROR etc. Can you actually compile that code? It would be better if you can present your question with less code. Ali
Re: Add compile time mutable variable type
On Tuesday, 5 June 2012 at 01:01:07 UTC, Chang Long wrote: I need a type can be change on compile time, it can be immutable or mutable at run time. For example : --- abstract class Template_parameter_Base{ TypeInto ti; string file ; size_t line l; string name ; this(TypeInto ti, string file, size_t line, string name){ this.ti = ti ; this.file = file ; this.line = line ; this.name = name ; } } class Template_parameter(T) : Template_parameter_Base { T value ; alias T this; void assign(ref T t){ value = t ; } } class Template { static compile_time_mutable(string[Template_parameter_Base]) template_vars ; void assign(string name, string __file__ = __FILE__, size_t __line__ =__LINE__, T)(T t) { static if( name in template_vars ){ static parameter = template_vars[name] ; } else { static parameter = template_vars[name] = new Template_parameter(typeid(T), __file__, __line__ ); } parameter.assign(t); } string render(){ // use template_vars comiplate a dynamic link lib , and load it, and put the template_vars to it, and run it , // if dynamic link lib already exists, or the templte file is not changed, just run it . } } void main(){ static tpl = new Template; auto is_login = false ; tpl.assign!"is_login"( is_login) ) ; if( is_login ) { tpl.assign!"user"( new User() ) ; } } --- Why I need this is because I need to know all parameters at first time call Template.render, but a lot parameter will not be call at run time. so I need a type can be changed at compile time. the new type is just like mutable type at CTFE. The previous two example is not correct, please see this one: abstract class Template_parameter_Base{ TypeInto ti; string file ; size_t line l; string name ; this(TypeInto ti, string file, size_t line, string name){ this.ti = ti ; this.file = file ; this.line = line ; this.name = name ; } } class Template_parameter(T) : Template_parameter_Base { T value ; alias T this; void assign(ref T t){ value = t ; } } class Template_Engine { string name ; Template_parameter_Base[string] parameters ; void this(string name) { this.name = name ; } } class Template (string name) { static compile_time_mutable(Template_Engine) engine = new Template_Engine(name) ; void assign(string name, string __file__ = __FILE__, size_t __line__ =__LINE__, T)(T t) { static if( name in engine.parameters ){ static compile_time_mutable(parameter) = engine.parameters[name] ; static assert( parameter.ti == typeid(T), "assign var at " ~ __file__ ~ " line" ~ __line__ " with type " ~ T.stringof " ~ conflict with old parameter at file " ~ parameter.file ~ " line " ~ parameter.line ); } else { static compile_time_mutable(parameter) = engine.parameters[name] = new Template_parameter(typeid(T), __file__, __line__ , name ); } // put the value to parameter at run time parameter.assign(t); } string render(){ // use the engine.parameters can know all parameter type information // use template_vars comiplate a dynamic link lib , and load it, and put the template_vars to it, and run it , // if dynamic link lib already exists, or the templte file is not changed, just run it . } } void main(){ static tpl = new Template!"home_page" ; auto is_login = false ; tpl.assign!"is_login"( is_login) ) ; if( is_login ) { tpl.assign!"user"( new User() ) ; } auto string switch_user = "new_user_email" ; if( switch_user !is null ) { tpl.assign!"user"( new User(switch_user) ) ; } tpl.assign!"user"( true ) ; // static assert error }
Re: Add compile time mutable variable type
On Tuesday, 5 June 2012 at 01:01:07 UTC, Chang Long wrote: I need a type can be change on compile time, it can be immutable or mutable at run time. For example : --- abstract class Template_parameter_Base{ TypeInto ti; string file ; size_t line l; string name ; this(TypeInto ti, string file, size_t line, string name){ this.ti = ti ; this.file = file ; this.line = line ; this.name = name ; } } class Template_parameter(T) : Template_parameter_Base { T value ; alias T this; void assign(ref T t){ value = t ; } } class Template { static compile_time_mutable(string[Template_parameter_Base]) template_vars ; void assign(string name, string __file__ = __FILE__, size_t __line__ =__LINE__, T)(T t) { static if( name in template_vars ){ static parameter = template_vars[name] ; } else { static parameter = template_vars[name] = new Template_parameter(typeid(T), __file__, __line__ ); } parameter.assign(t); } string render(){ // use template_vars comiplate a dynamic link lib , and load it, and put the template_vars to it, and run it , // if dynamic link lib already exists, or the templte file is not changed, just run it . } } void main(){ static tpl = new Template; auto is_login = false ; tpl.assign!"is_login"( is_login) ) ; if( is_login ) { tpl.assign!"user"( new User() ) ; } } --- Why I need this is because I need to know all parameters at first time call Template.render, but a lot parameter will not be call at run time. so I need a type can be changed at compile time. the new type is just like mutable type at CTFE. this example is more convincing: abstract class Template_parameter_Base{ TypeInto ti; string file ; size_t line l; string name ; this(TypeInto ti, string file, size_t line, string name){ this.ti = ti ; this.file = file ; this.line = line ; this.name = name ; } } class Template_parameter(T) : Template_parameter_Base { T value ; alias T this; void assign(ref T t){ value = t ; } } class Template { static compile_time_mutable(Template_parameter_Base[string]) template_vars ; void assign(string name, string __file__ = __FILE__, size_t __line__ =__LINE__, T)(T t) { static if( name in template_vars ){ static compile_time_mutable(parameter) = template_vars[name] ; static assert( parameter.ti == typeid(T), "assign var at " ~ __file__ ~ " line" ~ __line__ " with type " ~ T.stringof " ~ conflict with old parameter at file " ~ parameter.file ~ " line " ~ parameter.line ); } else { static compile_time_mutable(parameter) = template_vars[name] = new Template_parameter(typeid(T), __file__, __line__ , name ); } // put the value to parameter at run time parameter.assign(t); } string render(){ // use template_vars comiplate a dynamic link lib , and load it, and put the template_vars to it, and run it , // if dynamic link lib already exists, or the templte file is not changed, just run it . } } void main(){ static tpl = new Template; auto is_login = false ; tpl.assign!"is_login"( is_login) ) ; if( is_login ) { tpl.assign!"user"( new User() ) ; } auto string switch_user = "new_user_email" ; if( switch_user !is null ) { tpl.assign!"user"( new User(switch_user) ) ; } tpl.assign!"user"( true ) ; // static assert error }
Add compile time mutable variable type
I need a type can be change on compile time, it can be immutable or mutable at run time. For example : --- abstract class Template_parameter_Base{ TypeInto ti; string file ; size_t line l; string name ; this(TypeInto ti, string file, size_t line, string name){ this.ti = ti ; this.file = file ; this.line = line ; this.name = name ; } } class Template_parameter(T) : Template_parameter_Base { T value ; alias T this; void assign(ref T t){ value = t ; } } class Template { static compile_time_mutable(string[Template_parameter_Base]) template_vars ; void assign(string name, string __file__ = __FILE__, size_t __line__ =__LINE__, T)(T t) { static if( name in template_vars ){ static parameter = template_vars[name] ; } else { static parameter = template_vars[name] = new Template_parameter(typeid(T), __file__, __line__ ); } parameter.assign(t); } string render(){ // use template_vars comiplate a dynamic link lib , and load it, and put the template_vars to it, and run it , // if dynamic link lib already exists, or the templte file is not changed, just run it . } } void main(){ static tpl = new Template; auto is_login = false ; tpl.assign!"is_login"( is_login) ) ; if( is_login ) { tpl.assign!"user"( new User() ) ; } } --- Why I need this is because I need to know all parameters at first time call Template.render, but a lot parameter will not be call at run time. so I need a type can be changed at compile time. the new type is just like mutable type at CTFE.
Re: How mutable is immutable?
On 01/01/2012 10:40 AM, Denis Shelomovskij wrote: So, I'm a function `f`, I have an `immutable(type)[]` argument and I want to store it for my friend `g` in an TLS variable `v`: --- string v; debug string sure; void f(string s) { v = s; debug sure = s.idup; } void g() { assert(v == sure); } --- I also store a copy of `s` into `sure` for my friend to ensure immutable date hasn't been mutated. Can my friend's assertion ever fail without breaking a type-system? Sure. Just consider this: --- void main() { auto s = "abba".idup; f(s); delete s; g(); } --- Is it by-design? Looks like deleting immutable (and const because of implicit conversion) data should be prohibited. OK. Let `delete` be fixed. Can we still fail? --- void h() { immutable(char)[4] s = "abba"; f(s); } void main() { h(); g(); } --- Damn! So, what can we do with it? Not sure, but I have a proposal. Fix it in language: * disallow `delete` of const/immutable data * disallow immutable data on the stack This makes data really immutable if I don't miss something. Anyway, I want `immutable` qualified data to be immutable without breaking a type-system (if one do it, its his own responsibility), so some changes should be made (IMHO). You are using unsafe language features to break the type system. That is not the fault of the type system. '@safe:' at the top of the program should stop both examples from working, it is a bug that it does not.
How mutable is immutable?
So, I'm a function `f`, I have an `immutable(type)[]` argument and I want to store it for my friend `g` in an TLS variable `v`: --- string v; debug string sure; void f(string s) { v = s; debug sure = s.idup; } void g() { assert(v == sure); } --- I also store a copy of `s` into `sure` for my friend to ensure immutable date hasn't been mutated. Can my friend's assertion ever fail without breaking a type-system? Sure. Just consider this: --- void main() { auto s = "abba".idup; f(s); delete s; g(); } --- Is it by-design? Looks like deleting immutable (and const because of implicit conversion) data should be prohibited. OK. Let `delete` be fixed. Can we still fail? --- void h() { immutable(char)[4] s = "abba"; f(s); } void main() { h(); g(); } --- Damn! So, what can we do with it? Not sure, but I have a proposal. Fix it in language: * disallow `delete` of const/immutable data * disallow immutable data on the stack This makes data really immutable if I don't miss something. Anyway, I want `immutable` qualified data to be immutable without breaking a type-system (if one do it, its his own responsibility), so some changes should be made (IMHO).
Re: mutable compile-time data proposal
You missed the point. The case with dynamic libraries is just too obvious: they're "dynamic" for a reason. The case of base classes not knowing their derived classes is also kinda obvious because the mutable aliases would allow for derived classes to add themselves to the tuple by mixin in some compile-time stuff. You could do that if aliases would be compile-time rebindable, but you can't do it otherwise. On Thu, Dec 29, 2011 at 11:31 AM, Jonathan M Davis wrote: > On Thursday, December 29, 2011 10:23:11 Gor Gyolchanyan wrote: >> The mutability of compile-time data would essentially enable fully >> imperative compile-time computation. Right now it's almost purely >> functional with the small exception of CTFE functions. Sometimes >> functional style can't do the trick. For instance, you can't make a >> template which "returns" a TypeTuple of derived classes of the given >> class. > > You can't do that because the compiler doesn't have that information, not > because of the functional nature of much of the compile time stuff. Classes > don't know about their derived classes, and with the C linking model (which D > uses), you can't possibly know what they all are until link time - and with > dynamically loaded libraries, you won't even know then, because more can be > loaded and linked in at runtime. > > You should be able to do pretty much anything in a functional style that you > can do with an imperative style. You just have to go about it differently. > > - Jonathan M Davis -- Bye, Gor Gyolchanyan.
Re: mutable compile-time data proposal
On Thursday, December 29, 2011 10:23:11 Gor Gyolchanyan wrote: > The mutability of compile-time data would essentially enable fully > imperative compile-time computation. Right now it's almost purely > functional with the small exception of CTFE functions. Sometimes > functional style can't do the trick. For instance, you can't make a > template which "returns" a TypeTuple of derived classes of the given > class. You can't do that because the compiler doesn't have that information, not because of the functional nature of much of the compile time stuff. Classes don't know about their derived classes, and with the C linking model (which D uses), you can't possibly know what they all are until link time - and with dynamically loaded libraries, you won't even know then, because more can be loaded and linked in at runtime. You should be able to do pretty much anything in a functional style that you can do with an imperative style. You just have to go about it differently. - Jonathan M Davis
Re: mutable compile-time data proposal
The mutability of compile-time data would essentially enable fully imperative compile-time computation. Right now it's almost purely functional with the small exception of CTFE functions. Sometimes functional style can't do the trick. For instance, you can't make a template which "returns" a TypeTuple of derived classes of the given class. 2011/12/29 Mariusz Gliwiński : > David Nadlinger wrote: >> Could you show a few examples? I'm just curious, because I wrote a >> sizable chunk of D code, often incorporating some form of compile time >> magic, and never felt the need for it. > I'd rather avoid that because code i'm writing isn't a state of art, so you > might neglect my concrete ideas of solving things (use of tool). > Furthermore, i'm quite sleepy already so i might forget something, explain > wrongly. So, i hope i'm not ruining good idea by providing stupid examples. > > -- local CT variables, result to standard RT variable. > 1) Generate UUIDs of types of messages which are being provided and received > from various parts of application. > > -- global CT variables, not sure if we're talking about that now. > 2) Make sure there is only one provider, and one receiver (in couple of > cases). More generally, validation of application logic, that can be done > static, but can't be catched up by compiler itself. > > -- local CT variables, > 3) There are examples, where i'd like to avoid use of classes (i don't need > to put them in some container, and treat under superclass API), but i would > still like to share code (traits). So yes, i'm using mixins, but frequently > this kind of mixin needs initialization/dispose, which has to be called > manually by consumer. It leads to many initXTrait on initializer. I'd rather > like to store function pointers and iterate over it (i'm not even talking > about add something like this to language). > > 4) I'd like to generate application interface prototype during compilation > (serialization of specific parts of AST if i'm not wrong to use this term > here), and not having to write my own D parser for it. Yeah, i know you > probably got big WTF in your head while reading this, but these are things > i'd like to do, and neverthless if it's good or not, those are ideas that > programmer would like to have a chance to implement. > > I'm sure there are more appealing examples, but these are mine, and i'd like > to just have a possibility to implement them. -- Bye, Gor Gyolchanyan.
Re: mutable compile-time data proposal
David Nadlinger wrote: > Could you show a few examples? I'm just curious, because I wrote a > sizable chunk of D code, often incorporating some form of compile time > magic, and never felt the need for it. I'd rather avoid that because code i'm writing isn't a state of art, so you might neglect my concrete ideas of solving things (use of tool). Furthermore, i'm quite sleepy already so i might forget something, explain wrongly. So, i hope i'm not ruining good idea by providing stupid examples. -- local CT variables, result to standard RT variable. 1) Generate UUIDs of types of messages which are being provided and received from various parts of application. -- global CT variables, not sure if we're talking about that now. 2) Make sure there is only one provider, and one receiver (in couple of cases). More generally, validation of application logic, that can be done static, but can't be catched up by compiler itself. -- local CT variables, 3) There are examples, where i'd like to avoid use of classes (i don't need to put them in some container, and treat under superclass API), but i would still like to share code (traits). So yes, i'm using mixins, but frequently this kind of mixin needs initialization/dispose, which has to be called manually by consumer. It leads to many initXTrait on initializer. I'd rather like to store function pointers and iterate over it (i'm not even talking about add something like this to language). 4) I'd like to generate application interface prototype during compilation (serialization of specific parts of AST if i'm not wrong to use this term here), and not having to write my own D parser for it. Yeah, i know you probably got big WTF in your head while reading this, but these are things i'd like to do, and neverthless if it's good or not, those are ideas that programmer would like to have a chance to implement. I'm sure there are more appealing examples, but these are mine, and i'd like to just have a possibility to implement them.
Re: mutable compile-time data proposal
On 12/29/11 6:18 AM, Mariusz Gliwiński wrote: Andrei Alexandrescu wrote: I don't think such a feature has a huge potential use. I honestly think it's a "meh" feature. It's a feature for defining elaborate literals, and for that we have the shock and awe of mixin and CTFE. Actually, i already needed it few times in my D project (and still need). Could you show a few examples? I'm just curious, because I wrote a sizable chunk of D code, often incorporating some form of compile time magic, and never felt the need for it. Thanks, David
Re: mutable compile-time data proposal
On 12/28/2011 9:18 PM, Mariusz Gliwiński wrote: For me, question would be not "if it's useful", but "is it easy to implement and if it's not hurting compiler performance too much". I beg to differ. A feature should be "why", not "why not". Otherwise, we wind up with a complex boatload of semi-useless features.
Re: mutable compile-time data proposal
Andrei Alexandrescu wrote: > I don't think such a feature has a huge potential use. I honestly think > it's a "meh" feature. It's a feature for defining elaborate literals, > and for that we have the shock and awe of mixin and CTFE. Actually, i already needed it few times in my D project (and still need). I think people are just not used to treat compile-time as just another time of execution and they don't see value of it. While uneducated coder as me (advantage of seeing things with fresh eye) sees CTFE as natural thing to do when input data is known, and computation power is bigger than memory read && executable growth. Of course it might be done by preprocessing sources but that's a pain in the ass. For me, question would be not "if it's useful", but "is it easy to implement and if it's not hurting compiler performance too much".
Re: mutable compile-time data proposal
On 12/28/11 4:54 PM, Gor Gyolchanyan wrote: I think you are, because this depends on syntax; blank lines between them would break it. Still there would be a huge potential use for that feature. I don't think such a feature has a huge potential use. I honestly think it's a "meh" feature. It's a feature for defining elaborate literals, and for that we have the shock and awe of mixin and CTFE. Iota is present in Go, and I don't think it's gone anywhere past "meh"iness, even in Go which lacks better code generation features. Andrei
Re: mutable compile-time data proposal
On Wed, 28 Dec 2011 19:51:42 +0100, Andrei Alexandrescu wrote: On 12/28/11 12:22 PM, Martin Nowak wrote: On Wed, 28 Dec 2011 15:00:10 +0100, Gor Gyolchanyan wrote: This is something I was thinking about for a long time now. There seems to be absolutely no difference between T, const(T) and immutable(T) if T is a compile-time value (a enum or a local in CTFE). The possibility to mutate compile-time values (at compile time, of course) would allow very convenient techniques to be used for a number of purposes. And since in my hypothetical D compile-time data can be mutated, then a compile-time static this is required (especially for the next example). For instance, here's something I'd love to be able to do: class Base { mixin template Register() { ctStaticThis() // a placeholder for the real compile-time static this { Derived = TypeTuple!(Derived, typeof(this)); } } enum Derived = TypeTuple!(); } class Derived1: Base { mixin Register; } class Derived2: Base { mixin Register; } static assert(is(Base.Derived == TypeTuple!(Base, Derived1, Derived2))); Similar things would allow to quickly build extremely powerful and useful compile-time information, which is currently not possible to build. If mutable compile-time data is implemented, the entire compile-time computation in D would become just like the run-time one. I'd really like to see such a construct. enum __iota; enum Masks { A = (1 << __iota++), B = (1 << __iota++), C = (1 << __iota++), DMask = (0b11 << __iota), D0 = (1 << __iota++), D1 = (1 << __iota++), } static assert(__iota <= 32); Now this would depend on the order of semantic so it's not feasible. enum Masks { __iota = __LINE__, A = (1 << 0), B = (1 << __LINE__ - __iota), C = (1 << __LINE__ - __iota), DMask = (0b11 << __LINE__ - __iota), D0 = (1 << __LINE__ - __iota), D1 = (1 << __LINE__ - __iota), } Yeah, I'm jesting. Or am I??? Andrei :), but seriously using __LINE__ or __FILE__ to create unique ids just doesn't cut it.
Re: mutable compile-time data proposal
I think you are, because this depends on syntax; blank lines between them would break it. Still there would be a huge potential use for that feature. On Wed, Dec 28, 2011 at 10:51 PM, Andrei Alexandrescu wrote: > On 12/28/11 12:22 PM, Martin Nowak wrote: >> >> On Wed, 28 Dec 2011 15:00:10 +0100, Gor Gyolchanyan >> wrote: >> >>> This is something I was thinking about for a long time now. >>> >>> There seems to be absolutely no difference between T, const(T) and >>> immutable(T) if T is a compile-time value (a enum or a local in CTFE). >>> The possibility to mutate compile-time values (at compile time, of >>> course) would allow very convenient techniques to be used for a number >>> of purposes. >>> And since in my hypothetical D compile-time data can be mutated, then >>> a compile-time static this is required (especially for the next >>> example). >>> For instance, here's something I'd love to be able to do: >>> >>> class Base >>> { >>> mixin template Register() >>> { >>> ctStaticThis() // a placeholder for the real compile-time static this >>> { >>> Derived = TypeTuple!(Derived, typeof(this)); >>> } >>> } >>> >>> enum Derived = TypeTuple!(); >>> } >>> >>> class Derived1: Base >>> { >>> mixin Register; >>> } >>> >>> class Derived2: Base >>> { >>> mixin Register; >>> } >>> >>> static assert(is(Base.Derived == TypeTuple!(Base, Derived1, Derived2))); >>> >>> Similar things would allow to quickly build extremely powerful and >>> useful compile-time information, which is currently not possible to >>> build. >>> If mutable compile-time data is implemented, the entire compile-time >>> computation in D would become just like the run-time one. >>> >> >> I'd really like to see such a construct. >> >> enum __iota; >> >> enum Masks >> { >> A = (1 << __iota++), >> B = (1 << __iota++), >> C = (1 << __iota++), >> >> DMask = (0b11 << __iota), >> D0 = (1 << __iota++), >> D1 = (1 << __iota++), >> } >> >> static assert(__iota <= 32); >> >> Now this would depend on the order of semantic so it's not feasible. > > > enum Masks > { > __iota = __LINE__, A = (1 << 0), > B = (1 << __LINE__ - __iota), > C = (1 << __LINE__ - __iota), > DMask = (0b11 << __LINE__ - __iota), D0 = (1 << __LINE__ - __iota), > D1 = (1 << __LINE__ - __iota), > } > > Yeah, I'm jesting. Or am I??? > > > Andrei -- Bye, Gor Gyolchanyan.
Re: mutable compile-time data proposal
On 12/28/11 12:22 PM, Martin Nowak wrote: On Wed, 28 Dec 2011 15:00:10 +0100, Gor Gyolchanyan wrote: This is something I was thinking about for a long time now. There seems to be absolutely no difference between T, const(T) and immutable(T) if T is a compile-time value (a enum or a local in CTFE). The possibility to mutate compile-time values (at compile time, of course) would allow very convenient techniques to be used for a number of purposes. And since in my hypothetical D compile-time data can be mutated, then a compile-time static this is required (especially for the next example). For instance, here's something I'd love to be able to do: class Base { mixin template Register() { ctStaticThis() // a placeholder for the real compile-time static this { Derived = TypeTuple!(Derived, typeof(this)); } } enum Derived = TypeTuple!(); } class Derived1: Base { mixin Register; } class Derived2: Base { mixin Register; } static assert(is(Base.Derived == TypeTuple!(Base, Derived1, Derived2))); Similar things would allow to quickly build extremely powerful and useful compile-time information, which is currently not possible to build. If mutable compile-time data is implemented, the entire compile-time computation in D would become just like the run-time one. I'd really like to see such a construct. enum __iota; enum Masks { A = (1 << __iota++), B = (1 << __iota++), C = (1 << __iota++), DMask = (0b11 << __iota), D0 = (1 << __iota++), D1 = (1 << __iota++), } static assert(__iota <= 32); Now this would depend on the order of semantic so it's not feasible. enum Masks { __iota = __LINE__, A = (1 << 0), B = (1 << __LINE__ - __iota), C = (1 << __LINE__ - __iota), DMask = (0b11 << __LINE__ - __iota), D0 = (1 << __LINE__ - __iota), D1 = (1 << __LINE__ - __iota), } Yeah, I'm jesting. Or am I??? Andrei
Re: mutable compile-time data proposal
On Wed, 28 Dec 2011 15:00:10 +0100, Gor Gyolchanyan wrote: This is something I was thinking about for a long time now. There seems to be absolutely no difference between T, const(T) and immutable(T) if T is a compile-time value (a enum or a local in CTFE). The possibility to mutate compile-time values (at compile time, of course) would allow very convenient techniques to be used for a number of purposes. And since in my hypothetical D compile-time data can be mutated, then a compile-time static this is required (especially for the next example). For instance, here's something I'd love to be able to do: class Base { mixin template Register() { ctStaticThis() // a placeholder for the real compile-time static this { Derived = TypeTuple!(Derived, typeof(this)); } } enum Derived = TypeTuple!(); } class Derived1: Base { mixin Register; } class Derived2: Base { mixin Register; } static assert(is(Base.Derived == TypeTuple!(Base, Derived1, Derived2))); Similar things would allow to quickly build extremely powerful and useful compile-time information, which is currently not possible to build. If mutable compile-time data is implemented, the entire compile-time computation in D would become just like the run-time one. I'd really like to see such a construct. enum __iota; enum Masks { A = (1 << __iota++), B = (1 << __iota++), C = (1 << __iota++), DMask = (0b11 << __iota), D0 = (1 << __iota++), D1 = (1 << __iota++), } static assert(__iota <= 32); Now this would depend on the order of semantic so it's not feasible.
mutable compile-time data proposal
This is something I was thinking about for a long time now. There seems to be absolutely no difference between T, const(T) and immutable(T) if T is a compile-time value (a enum or a local in CTFE). The possibility to mutate compile-time values (at compile time, of course) would allow very convenient techniques to be used for a number of purposes. And since in my hypothetical D compile-time data can be mutated, then a compile-time static this is required (especially for the next example). For instance, here's something I'd love to be able to do: class Base { mixin template Register() { ctStaticThis() // a placeholder for the real compile-time static this { Derived = TypeTuple!(Derived, typeof(this)); } } enum Derived = TypeTuple!(); } class Derived1: Base { mixin Register; } class Derived2: Base { mixin Register; } static assert(is(Base.Derived == TypeTuple!(Base, Derived1, Derived2))); Similar things would allow to quickly build extremely powerful and useful compile-time information, which is currently not possible to build. If mutable compile-time data is implemented, the entire compile-time computation in D would become just like the run-time one. -- Bye, Gor Gyolchanyan.
Re: std.string.reverse() for mutable array of chars
Jonathan M Davis: > Well, it looks like Andrei had some free time this morning and figured it > out. > He has a pull request for it: Thanks you Andrei Alexandrescu and Jonathan :-) Bye, bearophile
Re: std.string.reverse() for mutable array of chars
On Friday, December 09, 2011 13:27:01 Jonathan M Davis wrote: > On Friday, December 09, 2011 12:44:37 bearophile wrote: > > Jonathan M Davis: > > > It sounded like you were, > > > > Right, I was :-) But you have changed my mind when you have explained me > > that nothing in std.algorithm is grapheme-aware. So I have reduced the > > amount of what I am asking for. > > So, now you're asking that char and wchar arrays be reversible with reverse > such that their code points are reversed (i.e. the result is the same as if > you reversed an array of dchar). Well, I'm not sure that you can actually do > that with the same efficiency. I'd have to think about it more. Regardless, > the implementation would be _really_ complicated in comparison to how > reverse works right now. char[] and wchar[] don't work with reverse, > because their elements aren't swappable. So, you can't just swap elements > as you iterate in from both ends. You'd have to be moving stuff off into > temporaries as you swapped them, because the code point on one side > wouldn't necessarily fit where the code point on the other side was, and in > the worst case (i.e. all of the code points on one half of the string are > multiple code units and all of those on the other side are single code > units), you'd pretty much end up having to copy half the array while you > waited for enough space to open up on one side to fit the characters from > the other side. So, regardless of whether it has the same computational > complexity as the current reverse, its memory requirements would be far > more. > > I don't think that the request is completely unreasonable, but also I'm not > sure it's acceptable for reverse to change its performance characteristics > as much as would be required for it to work with arrays of char or wchar - > particularly with regards to how much memory would be required. In general, > the performance characteristics of the algorithms in Phobos don't vary much > with regards to the type that that's used. I'm pretty sure that in terms of > big-o notation, the memory complexity wouldn't match (though I don't recall > exactly how big-o notation works with memory rather than computational > complexity). Well, it looks like Andrei had some free time this morning and figured it out. He has a pull request for it: https://github.com/D-Programming-Language/phobos/pull/359 - Jonathan M Davis
Re: std.string.reverse() for mutable array of chars
On Friday, December 09, 2011 12:44:37 bearophile wrote: > Jonathan M Davis: > > It sounded like you were, > > Right, I was :-) But you have changed my mind when you have explained me > that nothing in std.algorithm is grapheme-aware. So I have reduced the > amount of what I am asking for. So, now you're asking that char and wchar arrays be reversible with reverse such that their code points are reversed (i.e. the result is the same as if you reversed an array of dchar). Well, I'm not sure that you can actually do that with the same efficiency. I'd have to think about it more. Regardless, the implementation would be _really_ complicated in comparison to how reverse works right now. char[] and wchar[] don't work with reverse, because their elements aren't swappable. So, you can't just swap elements as you iterate in from both ends. You'd have to be moving stuff off into temporaries as you swapped them, because the code point on one side wouldn't necessarily fit where the code point on the other side was, and in the worst case (i.e. all of the code points on one half of the string are multiple code units and all of those on the other side are single code units), you'd pretty much end up having to copy half the array while you waited for enough space to open up on one side to fit the characters from the other side. So, regardless of whether it has the same computational complexity as the current reverse, its memory requirements would be far more. I don't think that the request is completely unreasonable, but also I'm not sure it's acceptable for reverse to change its performance characteristics as much as would be required for it to work with arrays of char or wchar - particularly with regards to how much memory would be required. In general, the performance characteristics of the algorithms in Phobos don't vary much with regards to the type that that's used. I'm pretty sure that in terms of big-o notation, the memory complexity wouldn't match (though I don't recall exactly how big-o notation works with memory rather than computational complexity). - Jonathan M Davis
Re: std.string.reverse() for mutable array of chars
Jonathan M Davis: > It sounded like you were, Right, I was :-) But you have changed my mind when you have explained me that nothing in std.algorithm is grapheme-aware. So I have reduced the amount of what I am asking for. Bye, bearophile
Re: std.string.reverse() for mutable array of chars
On Friday, December 09, 2011 06:15:04 bearophile wrote: > Jonathan M Davis: > > I don't expect that std.string will _ever_ be grapheme-aware or be > > processed by default as a range of graphemes. > > OK, let's forget about graphemes in this discussion. Now I am not asking for > a grapheme-aware reverse. It sounded like you were, because you were complaining about how dchar did an exact reversal of the code points rather than taking combining code points into account. - Jonathan M Davis
Re: std.string.reverse() for mutable array of chars
Jonathan M Davis: > I don't expect that std.string will _ever_ be grapheme-aware or be processed > by default as a range of graphemes. OK, let's forget about graphemes in this discussion. Now I am not asking for a grapheme-aware reverse. Bye, bearophile
Re: std.string.reverse() for mutable array of chars
On Friday, December 09, 2011 05:58:40 bearophile wrote: > Jonathan M Davis: > > And as I explained in bug# 7085, reverse's behavior with regards to > > dchar[] is completely correct. It's reversing the code points, _not_ > > the graphemes. > OK. Maybe I will open a differently worded enhancement request, for a > grapheme-aware std.string. > > If you want to reverse a char[], then cast it to ubyte[] and reverse > > that. If you want to reverse a wchar[], then cast it to ushort[] and > > reverse that. In Phobos, strings are ranges of dchar, so reverse is > > going to reverse code points. If you want it to reverse code units > > instead, then you just use the appropriate cast. There's no reason to > > have it reverse the code units and completely mess up unicode strings. > > I am not interested in reversing code units. Sorry if my post has led to > this wrong idea. For this specific problem I am not going to cast to > ubyte[] or ushort[] because it gives very wrong results. > > It's possible to write a "correct" (that doesn't take into account > graphemes) reverse even if you do not use casts, keeping the array as > char[] or wchar[], reversing the bytes, and then reversing the bytes of > each variable-length codepoint. This is what I was asking to an in-place > reverse(). I don't expect that std.string will _ever_ be grapheme-aware or be processed by default as a range of graphemes. That's far too expensive as far as performance goes. Rather, we're likely to have a wrapper and/or separate range-type which handles graphemes. Then if you want the extra correctness and are willing to pay the cost, you use that. As I understand it, std.regex does have the beginnings of such, but we do still need to have a range type of some variety (probably in std.utf) which fully supports graphemes. - Jonathan M Davis
Re: std.string.reverse() for mutable array of chars
Jonathan M Davis: > And as I explained in bug# 7085, reverse's behavior with regards to dchar[] > is > completely correct. It's reversing the code points, _not_ the graphemes. OK. Maybe I will open a differently worded enhancement request, for a grapheme-aware std.string. > If you want to reverse a char[], then cast it to ubyte[] and reverse that. If > you want to reverse a wchar[], then cast it to ushort[] and reverse that. In > Phobos, strings are ranges of dchar, so reverse is going to reverse code > points. If you want it to reverse code units instead, then you just use the > appropriate cast. There's no reason to have it reverse the code units and > completely mess up unicode strings. I am not interested in reversing code units. Sorry if my post has led to this wrong idea. For this specific problem I am not going to cast to ubyte[] or ushort[] because it gives very wrong results. It's possible to write a "correct" (that doesn't take into account graphemes) reverse even if you do not use casts, keeping the array as char[] or wchar[], reversing the bytes, and then reversing the bytes of each variable-length codepoint. This is what I was asking to an in-place reverse(). Bye, bearophile
Re: std.string.reverse() for mutable array of chars
On Friday, December 09, 2011 04:46:35 bearophile wrote: > Reversing an array of chars/wchars is a common enough operation (mutable > arrays often come from precedent operations that have built it). Currently > std.algorithm.reverse() can't be used: > > > import std.algorithm; > void main() { > dchar[] s1 = "hello"d.dup; > s1.reverse(); // OK > wchar[] s2 = "hello"w.dup; > s2.reverse(); // error > char[] s3 = "hello".dup; > s3.reverse(); // error > } > > > I suggest to add a char[]/wchar[] specialization to std.algorithm.reverse() > (or to add a std.string.reverse()), to make it work on those types too. > Generally std.algorithms don't work on UTF8/UTF16 because of the variable > length of its items, but for this specific algorithm I think this is not a > problem because: > > 1) Reversing an array is an O(n) operation, and decoding UTF adds a constant > overhead, so the computational complexity of reverse doesn't change. 2) If > you reverse an char[] or wchar[] the result will fit in the input array (is > this always true? Please tell me if this isn't true). It "just" needs to > correctly swap the bytes of multi-byte chars, and swap if there are > combined codepoints too. > > - - - - - - - - - - - - - - - - - - > > And I think std.algorithm.reverse() is sometimes buggy on a dchar[] (UTF32): > > > import std.algorithm: reverse; > void main() { > dchar[] txt = "\U0041\U0308\U0042"d.dup; > txt.reverse(); > assert(txt == "\U0042\U0308\U0041"d); > } > > > txt contains LATIN CAPITAL LETTER A, COMBINING DIAERESIS, LATIN CAPITAL > LETTER B (see bug 7084 for more details). > > A correct output for reversing txt is (LATIN CAPITAL LETTER B, LATIN CAPITAL > LETTER A, COMBINING DIAERESIS): > > "\U0042\U0041\U0308"d > > > See for some code: > http://stackoverflow.com/questions/199260/how-do-i-reverse-a-utf-8-string-in > -place > > See also: > http://d.puremagic.com/issues/show_bug.cgi?id=7085 > > Regarding the printing of unicode strings see also: > http://d.puremagic.com/issues/show_bug.cgi?id=7084 If you want to reverse a char[], then cast it to ubyte[] and reverse that. If you want to reverse a wchar[], then cast it to ushort[] and reverse that. In Phobos, strings are ranges of dchar, so reverse is going to reverse code points. If you want it to reverse code units instead, then you just use the appropriate cast. There's no reason to have it reverse the code units and completely mess up unicode strings. And as I explained in bug# 7085, reverse's behavior with regards to dchar[] is completely correct. It's reversing the code points, _not_ the graphemes. If you want to operate on graphemes, you need a range of graphemes, which Phobos does not yet support. Once it does (or if you implement it yourself), you can reverse a string based on graphemes if that's what you want to do. But as it stands, ranges of code points are the most advanced unicode construct that Phobos currently supports, so that's what its functions are going to operate on. - Jonathan M Davis
std.string.reverse() for mutable array of chars
Reversing an array of chars/wchars is a common enough operation (mutable arrays often come from precedent operations that have built it). Currently std.algorithm.reverse() can't be used: import std.algorithm; void main() { dchar[] s1 = "hello"d.dup; s1.reverse(); // OK wchar[] s2 = "hello"w.dup; s2.reverse(); // error char[] s3 = "hello".dup; s3.reverse(); // error } I suggest to add a char[]/wchar[] specialization to std.algorithm.reverse() (or to add a std.string.reverse()), to make it work on those types too. Generally std.algorithms don't work on UTF8/UTF16 because of the variable length of its items, but for this specific algorithm I think this is not a problem because: 1) Reversing an array is an O(n) operation, and decoding UTF adds a constant overhead, so the computational complexity of reverse doesn't change. 2) If you reverse an char[] or wchar[] the result will fit in the input array (is this always true? Please tell me if this isn't true). It "just" needs to correctly swap the bytes of multi-byte chars, and swap if there are combined codepoints too. - - - - - - - - - - - - - - - - - - And I think std.algorithm.reverse() is sometimes buggy on a dchar[] (UTF32): import std.algorithm: reverse; void main() { dchar[] txt = "\U0041\U0308\U0042"d.dup; txt.reverse(); assert(txt == "\U0042\U0308\U0041"d); } txt contains LATIN CAPITAL LETTER A, COMBINING DIAERESIS, LATIN CAPITAL LETTER B (see bug 7084 for more details). A correct output for reversing txt is (LATIN CAPITAL LETTER B, LATIN CAPITAL LETTER A, COMBINING DIAERESIS): "\U0042\U0041\U0308"d See for some code: http://stackoverflow.com/questions/199260/how-do-i-reverse-a-utf-8-string-in-place See also: http://d.puremagic.com/issues/show_bug.cgi?id=7085 Regarding the printing of unicode strings see also: http://d.puremagic.com/issues/show_bug.cgi?id=7084 Bye, bearophile
Re: " is not mutable" when using ref return type
On Fri, 20 May 2011 14:42:57 -0400, Jonathan M Davis wrote: On Thu, 19 May 2011 00:22:42 -0400, Jonathan M Davis wrote: > On 2011-05-18 20:55, %u wrote: >> Hi! >> >> Is this a bug, or is it intentional that this fails? I can't come up >> with any case where it would cause a problem, but the compiler doesn't >> >> like the fact that there's a const in the structure: >> struct Temp { const int a; int b; } >> >> auto ref foo(Temp* t) { return *t; } //Error > > As soon as you do *t, you're copying the value. That's not true, if it's ref, it just copies the reference. Well, I wasn't sure either way, and when I tested it by creating a postblit which printed, it printed. So, either I ran into a bug (quite possible), or I definitely misunderstood what was going on. It depends on the example, if you are assigning the result to another variable, that is where the copy may occur. But if you do something like just take the address of the return, or pass it to something else that accepts ref, it should not call the postblit. Most certainly it's not within the function. -Steve
Re: " is not mutable" when using ref return type
> On Thu, 19 May 2011 00:22:42 -0400, Jonathan M Davis > > wrote: > > On 2011-05-18 20:55, %u wrote: > >> Hi! > >> > >> Is this a bug, or is it intentional that this fails? I can't come up > >> with any case where it would cause a problem, but the compiler doesn't > >> > >> like the fact that there's a const in the structure: > >> struct Temp { const int a; int b; } > >> > >> auto ref foo(Temp* t) { return *t; } //Error > > > > As soon as you do *t, you're copying the value. > > That's not true, if it's ref, it just copies the reference. Well, I wasn't sure either way, and when I tested it by creating a postblit which printed, it printed. So, either I ran into a bug (quite possible), or I definitely misunderstood what was going on. - Jonathan M Davis
Re: " is not mutable" when using ref return type
On 19/05/11 1:25 PM, %u wrote: Hi! Is this a bug, or is it intentional that this fails? I can't come up with any case where it would cause a problem, but the compiler doesn't like the fact that there's a const in the structure: struct Temp { const int a; int b; } auto ref foo(Temp* t) { return *t; } //Error Just about all D type modifier keywords like const, shared, immutable and friends are completely broken semantically (i.e. TFBR**) and so there is very little hope that there will ever be a fix for these type system issue problems. (** TFBR Totally fucked beyond repair) Muffin's tip on the programming languages stocks (aka the PLS-2011 index) is to stay with your current investment in D2 for as long as the proprietary digitalmars implementation serves your purpose and to short sell otherwise. This is code for saying that the open source world is unlikely to ever provide any alternative to the currently available bug-ridden proprietary implementation of D2 which is itself, as a language specification, is riddled with bugs. Unfortunately there is no options market on D stock so that those of you that might be thinking of doing a PUT or CALL on D will be as bitterly disappointed as others that have tried to measure temperature in a vaccuum. xxx
Re: " is not mutable" when using ref return type
On Thu, 19 May 2011 00:22:42 -0400, Jonathan M Davis wrote: On 2011-05-18 20:55, %u wrote: Hi! Is this a bug, or is it intentional that this fails? I can't come up with any case where it would cause a problem, but the compiler doesn't like the fact that there's a const in the structure: struct Temp { const int a; int b; } auto ref foo(Temp* t) { return *t; } //Error As soon as you do *t, you're copying the value. That's not true, if it's ref, it just copies the reference. example: void foo(ref int i) { i = 5; } void main() { int i; int *p = &i; foo(*p); assert(i == 5); } To further drive home the point, this actually compiles: Temp foo(Temp* t) { return *t; } // no error There should be no restrictions on returning ref there, no matter what's inside Temp. Definitely a bug with the original, please file with bugzilla. -Steve
Re: " is not mutable" when using ref return type
On 2011-05-18 21:52, Mehrdad wrote: > On 5/18/2011 9:22 PM, Jonathan M Davis wrote: > > On 2011-05-18 20:55, %u wrote: > >> Hi! > >> > >> Is this a bug, or is it intentional that this fails? I can't come up > >> with any case where it would cause a problem, but the compiler doesn't > >> > >> like the fact that there's a const in the structure: > >> struct Temp { const int a; int b; } > >> > >> auto ref foo(Temp* t) { return *t; } //Error > > > > As soon as you do *t, you're copying the value. As such, I don't know why > > the ref is working at all. And it's impossible to assign to a struct > > with a const or immutable member, so the struct is not mutable. Why > > that's a problem here... My guess would be that it's a bug relating to > > copying from or assigning to const. If you declare this(this), you'll > > notice that it doesn't currently work with const, and if declared, > > this(this) would be called upon copying the struct. Still, something > > like > > > > auto t = Temp(); > > auto u = t; > > > > works with your definition of Temp, so just copying a non-mutable struct > > works as long as it doesn't declare this(this). It's probably treating > > auto ref as if it must be mutable or something like that, and Temp > > isn't. But I don't know what the problem is exactly. > > > > In any case, I would definitely advise that you _not_ create structs with > > const or immutable values, because you can never reassign to them, which > > causes all kinds of fun problems - including making it very hard to use > > them in arrays (_any_ place that would use Temp.init is stuck with > > Temp.init). It's generally better to just make the variables private and > > provide @property functions for getting the variables but not provide > > any for setting them. That way, they're read-only and you can still > > re-assign the whole struct if need be. > > > > - Jonathan M davis > > By the way, it doesn't matter if I use auto or not. It does the same > thing if I say "ref Temp". > > Interesting notes about postblit and everything, I'll keep those in > mind, thanks! If I wasn't clear enough, postblit is _supposed_ to work with const but currently doesn't. I wasn't saying that it won't ever, just that it's currently broken. http://d.puremagic.com/issues/show_bug.cgi?id=4867 - Jonathan M Davis
Re: " is not mutable" when using ref return type
On 5/18/2011 9:22 PM, Jonathan M Davis wrote: On 2011-05-18 20:55, %u wrote: Hi! Is this a bug, or is it intentional that this fails? I can't come up with any case where it would cause a problem, but the compiler doesn't like the fact that there's a const in the structure: struct Temp { const int a; int b; } auto ref foo(Temp* t) { return *t; } //Error As soon as you do *t, you're copying the value. As such, I don't know why the ref is working at all. And it's impossible to assign to a struct with a const or immutable member, so the struct is not mutable. Why that's a problem here... My guess would be that it's a bug relating to copying from or assigning to const. If you declare this(this), you'll notice that it doesn't currently work with const, and if declared, this(this) would be called upon copying the struct. Still, something like auto t = Temp(); auto u = t; works with your definition of Temp, so just copying a non-mutable struct works as long as it doesn't declare this(this). It's probably treating auto ref as if it must be mutable or something like that, and Temp isn't. But I don't know what the problem is exactly. In any case, I would definitely advise that you _not_ create structs with const or immutable values, because you can never reassign to them, which causes all kinds of fun problems - including making it very hard to use them in arrays (_any_ place that would use Temp.init is stuck with Temp.init). It's generally better to just make the variables private and provide @property functions for getting the variables but not provide any for setting them. That way, they're read-only and you can still re-assign the whole struct if need be. - Jonathan M davis By the way, it doesn't matter if I use auto or not. It does the same thing if I say "ref Temp". Interesting notes about postblit and everything, I'll keep those in mind, thanks!
Re: " is not mutable" when using ref return type
On 2011-05-18 20:55, %u wrote: > Hi! > > Is this a bug, or is it intentional that this fails? I can't come up > with any case where it would cause a problem, but the compiler doesn't > like the fact that there's a const in the structure: > > struct Temp { const int a; int b; } > > auto ref foo(Temp* t) { return *t; } //Error As soon as you do *t, you're copying the value. As such, I don't know why the ref is working at all. And it's impossible to assign to a struct with a const or immutable member, so the struct is not mutable. Why that's a problem here... My guess would be that it's a bug relating to copying from or assigning to const. If you declare this(this), you'll notice that it doesn't currently work with const, and if declared, this(this) would be called upon copying the struct. Still, something like auto t = Temp(); auto u = t; works with your definition of Temp, so just copying a non-mutable struct works as long as it doesn't declare this(this). It's probably treating auto ref as if it must be mutable or something like that, and Temp isn't. But I don't know what the problem is exactly. In any case, I would definitely advise that you _not_ create structs with const or immutable values, because you can never reassign to them, which causes all kinds of fun problems - including making it very hard to use them in arrays (_any_ place that would use Temp.init is stuck with Temp.init). It's generally better to just make the variables private and provide @property functions for getting the variables but not provide any for setting them. That way, they're read-only and you can still re-assign the whole struct if need be. - Jonathan M davis
" is not mutable" when using ref return type
Hi! Is this a bug, or is it intentional that this fails? I can't come up with any case where it would cause a problem, but the compiler doesn't like the fact that there's a const in the structure: struct Temp { const int a; int b; } auto ref foo(Temp* t) { return *t; } //Error
Re: Should conversion of mutable return value to immutable allowed?
Ali Çehreli napisał: > Implicit conversions to immutable in the following two functions feel > harmless. Has this been discussed before? > > string foo() > { > char[] s; > return s; // Error: cannot implicitly convert expression >//(s) of type char[] to string > } > > string bar() > { > char[] s; > return s ~ s; // Error: cannot implicitly convert expression >//(s ~ s) of type char[] to string > } > > Is there a reason why that's not possible? I am sure there must be other > cases that at least I would find harmless. :) Indeed. The returned object can be safely set to stone when its only aliases to the outside world point to immutable data. Such a guarantee is expressed in today's language by marking the function pure and all its arguments immutable. The conversion is currently not allowed as the above virtue of immutably pure functions was discovered not too long ago. If you want it, vote up: http://d.puremagic.com/issues/show_bug.cgi?id=5081 -- Tomek
Re: Should conversion of mutable return value to immutable allowed?
Also there is std.exception.assumUnique()
Re: Should conversion of mutable return value to immutable allowed?
Ali Ãehreli Wrote: > I have another question: Does calling .idup copy any data below? > > string foo() > { > char[] s; > return s.idup; // Is the content copied? > } > > Ali > Yes, dup stands for duplicate and is a property of arrays. There was discussion for allowing immutable objects to be created and return from pure functions.
Re: Should conversion of mutable return value to immutable allowed?
On 24.02.2011 19:08, Ali Çehreli wrote: Implicit conversions to immutable in the following two functions feel harmless. Has this been discussed before? string foo() { char[] s; return s; // Error: cannot implicitly convert expression // (s) of type char[] to string } string bar() { char[] s; return s ~ s; // Error: cannot implicitly convert expression // (s ~ s) of type char[] to string } Is there a reason why that's not possible? I am sure there must be other cases that at least I would find harmless. :) Ali Currently, the correct way to do it is to use the phobos function assumeUnique, like: string bar() { char[] s; return assumeUnique(s); } Note that this does only little more than casting to immutable, so you have to ensure there is no mutable reference left behind. Anyway, it might be nice if the compiler could detect some trivial cases and insert the cast appropriately. But on the other hand, the compiler will never to be able to auto-detect all cases, and so its cleaner to use assumeUnique explicitly. - Krox
Re: Should conversion of mutable return value to immutable allowed?
On 02/24/2011 10:28 AM, spir wrote: > On 02/24/2011 07:08 PM, Ali Çehreli wrote: >> Implicit conversions to immutable in the following two functions feel >> harmless. >> Has this been discussed before? >> >> string foo() >> { >> char[] s; >> return s; // Error: cannot implicitly convert expression >> // (s) of type char[] to string >> } >> >> string bar() >> { >> char[] s; >> return s ~ s; // Error: cannot implicitly convert expression >> // (s ~ s) of type char[] to string >> } >> >> Is there a reason why that's not possible? I am sure there must be >> other cases >> that at least I would find harmless. :) >> >> Ali > > I'm all for that. Can hardly how auto conversion in the sense mutable > --> immutable could be harmful, but may miss a meaningful point. It shouldn't be allowed if a reference to that char[] is left behind. Otherwise although the receiver would think that the data wouldn't change; it could be changed by that other reference. struct S { char[] s; string foo() { return s;// <-- Must not be allowed } } But when the object in question is about to go out of scope? I don't know. On the other hand, reducing some implicit behavior is also good. > This > would esp be nice for strings, since we regularly need to use char > arrays to construct textual content. > > Denis I have another question: Does calling .idup copy any data below? string foo() { char[] s; return s.idup; // Is the content copied? } Ali
Re: Should conversion of mutable return value to immutable allowed?
On 02/24/2011 07:08 PM, Ali Çehreli wrote: Implicit conversions to immutable in the following two functions feel harmless. Has this been discussed before? string foo() { char[] s; return s; // Error: cannot implicitly convert expression // (s) of type char[] to string } string bar() { char[] s; return s ~ s; // Error: cannot implicitly convert expression // (s ~ s) of type char[] to string } Is there a reason why that's not possible? I am sure there must be other cases that at least I would find harmless. :) Ali I'm all for that. Can hardly how auto conversion in the sense mutable --> immutable could be harmful, but may miss a meaningful point. This would esp be nice for strings, since we regularly need to use char arrays to construct textual content. Denis -- _ vita es estrany spir.wikidot.com
Should conversion of mutable return value to immutable allowed?
Implicit conversions to immutable in the following two functions feel harmless. Has this been discussed before? string foo() { char[] s; return s; // Error: cannot implicitly convert expression //(s) of type char[] to string } string bar() { char[] s; return s ~ s; // Error: cannot implicitly convert expression //(s ~ s) of type char[] to string } Is there a reason why that's not possible? I am sure there must be other cases that at least I would find harmless. :) Ali
Re: Logical Const using a Mutable template
Jesse Phillips Wrote: > The rules for this are: > > * Only mutable data can be assigned to a Mutable > * Modification of referenced fields can be modified (inner class fields, > pointer targets) > > I'll be back to finish this in a bit. * Value types can be modified if the encapsulating class is not declared const/immutable And I have come up with 2 major concerns related to immutable classes. Would an inner class be placed in read-only memory in instantiating an immutable class: class A { Mutable!(Inner) innerclass; this() { innerclass = new Inner; } // Is innerclass placed in read-only memory } new immutable(A); And what about when an immutable instance is passed to a thread or network. Would the innerclass be placed in read-only memory for the new thread/machine. And looking over it again, I found that I wasn't using the opAssign const functions, they didn't meet the requirements. So I think a working alias this would allow the template to be: (The important check being that Mutables are unqualified) struct Mutable( T ) if ( is( T : Unqual!T ) ) { private T _payload; this( T t ) { _payload = t; } @trusted @property ref T get( )( ) const { T* p = cast( T* )&_payload; return *p; } alias get this; } https://gist.github.com/721066
Re: Logical Const using a Mutable template
Max Samukha Wrote: > On 11/30/2010 09:30 AM, Jesse Phillips wrote: > > This came up in discussion and I think the behavior is safe and usable when > > wanting to change class data in a const function. > > > > http://article.gmane.org/gmane.comp.lang.d.general/43476 > > > > One limitation is that value types declared as Mutable (Mutable!(int)) can > > not be changed if the encapsulating class is declared immutable. For this > > reason a Mutable value can not be changed inside a const function. I think > > this is acceptable. > > > > Another limitation appears to be an issue with alias this. It is commented > > as a //FIXME in the code. > > > > https://gist.github.com/721066 > > It is not enough to forward opAssign and opEquals. Any operator should > be handled. For example, change the implementation of A.foo to > > n2 += 1; > > and you will get a segfault during compilation. > > You could add more kludge with operator overloads but I don't think it > is worth the effort. It makes more sense to wait until "alias this" bugs > are fixed. On the other hand, we may wait forever since the way "alias > this" should handle operators has never been specified. > The intent isn't to work around alias this bugs. It is to provide mutation in a const function, but with the guarantee that it will not result in undefined behavior. (I should have stated that first, but it was getting late). Concurrency shouldn't be any different from having a reference in a class you are sharing. Sharing immutable objects should be fine as they still can not have their state changed. The rules for this are: * Only mutable data can be assigned to a Mutable * Modification of referenced fields can be modified (inner class fields, pointer targets) I'll be back to finish this in a bit.
Re: Logical Const using a Mutable template
On 11/30/2010 09:30 AM, Jesse Phillips wrote: This came up in discussion and I think the behavior is safe and usable when wanting to change class data in a const function. http://article.gmane.org/gmane.comp.lang.d.general/43476 One limitation is that value types declared as Mutable (Mutable!(int)) can not be changed if the encapsulating class is declared immutable. For this reason a Mutable value can not be changed inside a const function. I think this is acceptable. Another limitation appears to be an issue with alias this. It is commented as a //FIXME in the code. https://gist.github.com/721066 An example usage looks like: class Inner { int n; } class A { Mutable!(int*) n; Mutable!(int) n2; Mutable!(Inner) innerClass; this() { n = new int; innerClass = new Inner; } void foo( int num ) { n2 = num; } void bar( int num ) const { innerClass.n = num; } } auto aImmu = new immutable(A); auto aMu = new A; int i = 8; *aImmu.n = i, aImmu.bar(6), *aMu.n = i, aMu.n =&i, aMu.n2 = i, aMu.bar(6), aMu.foo(6), It is not enough to forward opAssign and opEquals. Any operator should be handled. For example, change the implementation of A.foo to n2 += 1; and you will get a segfault during compilation. You could add more kludge with operator overloads but I don't think it is worth the effort. It makes more sense to wait until "alias this" bugs are fixed. On the other hand, we may wait forever since the way "alias this" should handle operators has never been specified.
Logical Const using a Mutable template
This came up in discussion and I think the behavior is safe and usable when wanting to change class data in a const function. http://article.gmane.org/gmane.comp.lang.d.general/43476 One limitation is that value types declared as Mutable (Mutable!(int)) can not be changed if the encapsulating class is declared immutable. For this reason a Mutable value can not be changed inside a const function. I think this is acceptable. Another limitation appears to be an issue with alias this. It is commented as a //FIXME in the code. https://gist.github.com/721066 An example usage looks like: class Inner { int n; } class A { Mutable!(int*) n; Mutable!(int) n2; Mutable!(Inner) innerClass; this() { n = new int; innerClass = new Inner; } void foo( int num ) { n2 = num; } void bar( int num ) const { innerClass.n = num; } } auto aImmu = new immutable(A); auto aMu = new A; int i = 8; *aImmu.n = i, aImmu.bar(6), *aMu.n = i, aMu.n = &i, aMu.n2 = i, aMu.bar(6), aMu.foo(6),
Re: main.d(61): Error: temp_[i_] isn't mutable
On 06/21/2010 03:37 AM, Ben Hanson wrote: I'm currently using strings for the regex strings themselves. In lexertl, I use templated free functions what work with iterators, which means input can come from different sources. This sounds like the kind of thing you are talking about? Regards, Ben Sounds about right! Andrei
Re: main.d(61): Error: temp_[i_] isn't mutable
Hi Andrei, == Quote from Andrei Alexandrescu (seewebsiteforem...@erdani.org)'s article > On 06/20/2010 12:56 PM, Ali Çehreli wrote: > > Ben Hanson wrote: > >> == Quote from Justin Spahr-Summers (justin.spahrsumm...@gmail.com)'s > >>> "string" is actually an alias for "immutable(char)[]" (and > >> similarly for > >>> the other string types), so its contents are not modifiable, though > >> its > >>> length can be adjusted and contents appended. If you need to be > >> able to > >>> modify the characters, just use char[] instead. You can then use the > >>> .idup property to get a string afterward. > >> > >> I'm converted temp_ to CharT[] as suggested, but the conversion back > >> to a string is failing: > >> > >> _charset = temp_.idup; > >> > >> main.d(76): Error: cannot implicitly convert expression (_adDupT((& > >> D58TypeInfo_AT4main14__T5regexTAyaZ18basic_string_token5CharT6__initZ),cast > >> > >> (string)temp_)) of type immutable(CharT)[] to string > > > > > > Would it work for you if the regex template took the character type > > instead of the string type? > > > > The relevant lines: > > > > template regex(CharT) > > { > > // ... > > alias CharT[] StringT; > > StringT _charset; > > enum size_t MAX_CHARS = CharT.max + 1; > > // ... > > _charset = squeeze(_charset.idup).dup; > > > > And then, in main: > > > > regex!(char).basic_string_token token_; > > > > Ali > IMHO it's more general if the regexp took the string type as a > parameter. This is because later that is easier generalizable to > accepting a range that's different from an array. > My dream: to have a compile-time-generated regex engine that can operate > on any input stream. > Andrei I'm currently using strings for the regex strings themselves. In lexertl, I use templated free functions what work with iterators, which means input can come from different sources. This sounds like the kind of thing you are talking about? Regards, Ben
Re: main.d(61): Error: temp_[i_] isn't mutable
On 06/20/2010 02:29 PM, Ali Çehreli wrote: Andrei Alexandrescu wrote: > IMHO it's more general if the regexp took the string type as a > parameter. This is because later that is easier generalizable to > accepting a range that's different from an array. Agreed. Given T which may be an immutable type, what is the cleanest way of creating a mutable copy of that type? typeof(array.dup) works on arrays but what if T is a value type or any type where .dup doesn't exist? Ali std.conv.to should work with most sensible combinations. Andrei
Re: main.d(61): Error: temp_[i_] isn't mutable
Andrei Alexandrescu wrote: > IMHO it's more general if the regexp took the string type as a > parameter. This is because later that is easier generalizable to > accepting a range that's different from an array. Agreed. Given T which may be an immutable type, what is the cleanest way of creating a mutable copy of that type? typeof(array.dup) works on arrays but what if T is a value type or any type where .dup doesn't exist? Ali
Re: main.d(61): Error: temp_[i_] isn't mutable
On 06/20/2010 07:01 AM, Ben Hanson wrote: == Quote from Justin Spahr-Summers (justin.spahrsumm...@gmail.com)'s "string" is actually an alias for "immutable(char)[]" (and similarly for the other string types), so its contents are not modifiable, though its length can be adjusted and contents appended. If you need to be able to modify the characters, just use char[] instead. You can then use the .idup property to get a string afterward. I'm converted temp_ to CharT[] as suggested, but the conversion back to a string is failing: _charset = temp_.idup; main.d(76): Error: cannot implicitly convert expression (_adDupT((& D58TypeInfo_AT4main14__T5regexTAyaZ18basic_string_token5CharT6__initZ),cast (string)temp_)) of type immutable(CharT)[] to string import std.conv; ... _charset = to!(typeof(_charset))(temp_); "to" converts strings of any width and mutability to strings of any width and mutability. Andrei
Re: main.d(61): Error: temp_[i_] isn't mutable
On Sun, 20 Jun 2010 12:01:31 + (UTC), Ben Hanson wrote: > > == Quote from Justin Spahr-Summers (justin.spahrsumm...@gmail.com)'s > > "string" is actually an alias for "immutable(char)[]" (and > similarly for > > the other string types), so its contents are not modifiable, though > its > > length can be adjusted and contents appended. If you need to be > able to > > modify the characters, just use char[] instead. You can then use the > > .idup property to get a string afterward. > > I'm converted temp_ to CharT[] as suggested, but the conversion back > to a string is failing: > > _charset = temp_.idup; > > main.d(76): Error: cannot implicitly convert expression (_adDupT((& > D58TypeInfo_AT4main14__T5regexTAyaZ18basic_string_token5CharT6__initZ),cast > (string)temp_)) of type immutable(CharT)[] to string Sorry I missed this on the first run through. Since you're using typedef to create your CharT type, it will create a type independent from all the others, meaning no implicit casts to or from it. "alias" is the equivalent to a C/C++ "typedef", and that should fix the compilation error.
Re: main.d(61): Error: temp_[i_] isn't mutable
On 06/20/2010 12:56 PM, Ali Çehreli wrote: Ben Hanson wrote: == Quote from Justin Spahr-Summers (justin.spahrsumm...@gmail.com)'s "string" is actually an alias for "immutable(char)[]" (and similarly for the other string types), so its contents are not modifiable, though its length can be adjusted and contents appended. If you need to be able to modify the characters, just use char[] instead. You can then use the .idup property to get a string afterward. I'm converted temp_ to CharT[] as suggested, but the conversion back to a string is failing: _charset = temp_.idup; main.d(76): Error: cannot implicitly convert expression (_adDupT((& D58TypeInfo_AT4main14__T5regexTAyaZ18basic_string_token5CharT6__initZ),cast (string)temp_)) of type immutable(CharT)[] to string Would it work for you if the regex template took the character type instead of the string type? The relevant lines: template regex(CharT) { // ... alias CharT[] StringT; StringT _charset; enum size_t MAX_CHARS = CharT.max + 1; // ... _charset = squeeze(_charset.idup).dup; And then, in main: regex!(char).basic_string_token token_; Ali IMHO it's more general if the regexp took the string type as a parameter. This is because later that is easier generalizable to accepting a range that's different from an array. My dream: to have a compile-time-generated regex engine that can operate on any input stream. Andrei