digitalmars.D - Read-only property without property
- Steven Schveighoffer (20/20) Sep 26 2014 I wanted to bring this over from D.learn, because I've never seen this
- Andrei Alexandrescu (2/21) Sep 26 2014 Very interesting!! -- Andrei
- John Colvin (5/26) Sep 26 2014 I've often thought of such approaches, but not used them for fear
- ketmar via Digitalmars-d (5/6) Sep 26 2014 it should not incur any problems. and if such code faults, it's a bug
- ketmar via Digitalmars-d (4/6) Sep 26 2014 On Fri, 26 Sep 2014 15:47:15 -0400
- H. S. Teoh via Digitalmars-d (13/27) Sep 26 2014 [...]
- Steven Schveighoffer (4/5) Sep 26 2014 Hm... good point, I'm not sure if unions are considered @safe. But I
- Andrei Alexandrescu (2/6) Sep 26 2014 I'd say certain unions may be deemed safe. -- Andrei
- H. S. Teoh via Digitalmars-d (31/40) Sep 26 2014 Hmm. I tried playing with the idea of unions being safe if all members
- H. S. Teoh via Digitalmars-d (7/25) Sep 26 2014 https://issues.dlang.org/show_bug.cgi?id=13536
- H. S. Teoh via Digitalmars-d (16/22) Sep 26 2014 [...]
- Steven Schveighoffer (38/57) Sep 26 2014 Well, if all unions members are of the same base type, and they only
- H. S. Teoh via Digitalmars-d (13/83) Sep 26 2014 [...]
- Steven Schveighoffer (16/25) Sep 26 2014 It makes sense that you can declare unsafe unions, because a declaration...
- H. S. Teoh via Digitalmars-d (30/62) Sep 26 2014 Argh, looks like another incompletely-implemented part of the compiler:
- Daniel Murphy (15/27) Sep 27 2014 This looks perfectly fine to me. Consider if you replaced all uses of t...
- Steven Schveighoffer (32/48) Sep 27 2014 I think that this is equivalent to u.q++, since the ++ does not apply to...
- Andrei Alexandrescu (2/14) Sep 26 2014 Nice! We need a complete set of rules for this stuff. -- Andrei
- Andrei Alexandrescu (3/22) Sep 26 2014 Unions mixing pointers and integrals aren't safe. Those mixing e.g. a
- Cliff (20/41) Sep 26 2014 This is a clever syntax, but I can't say I particularly care for
- Kapps (9/29) Sep 26 2014 C#'s way of declaring properties is something I've been missing
- Daniel N (13/34) Sep 26 2014 Thanks, I love this!
I wanted to bring this over from D.learn, because I've never seen this before, and it's an interesting solution to creating a property without much boilerplate. So here it is: class Foo { union { private int _a; // accessible only in this module public const int a; // accessible from anywhere, but read only } } And it works now, probably has for a while. Thoughts? This can easily be boilerplated in something like roprop!(int, "a") I am really not sure what union does to compiler optimization or runtime concerns, if it has any significant drawbacks. From what I can tell, it's a valid solution. Credit to Mark Schütz for the idea. -Steve
Sep 26 2014
On 9/26/14, 12:47 PM, Steven Schveighoffer wrote:I wanted to bring this over from D.learn, because I've never seen this before, and it's an interesting solution to creating a property without much boilerplate. So here it is: class Foo { union { private int _a; // accessible only in this module public const int a; // accessible from anywhere, but read only } } And it works now, probably has for a while. Thoughts? This can easily be boilerplated in something like roprop!(int, "a") I am really not sure what union does to compiler optimization or runtime concerns, if it has any significant drawbacks. From what I can tell, it's a valid solution. Credit to Mark Schütz for the idea.Very interesting!! -- Andrei
Sep 26 2014
On Friday, 26 September 2014 at 19:47:15 UTC, Steven Schveighoffer wrote:I wanted to bring this over from D.learn, because I've never seen this before, and it's an interesting solution to creating a property without much boilerplate. So here it is: class Foo { union { private int _a; // accessible only in this module public const int a; // accessible from anywhere, but read only } } And it works now, probably has for a while. Thoughts? This can easily be boilerplated in something like roprop!(int, "a") I am really not sure what union does to compiler optimization or runtime concerns, if it has any significant drawbacks. From what I can tell, it's a valid solution. Credit to Mark Schütz for the idea. -SteveI've often thought of such approaches, but not used them for fear of causing some horrible undefined behaviour (whether intentional or via a compiler bug). Are my fears misplaced?
Sep 26 2014
On Fri, 26 Sep 2014 22:09:12 +0000 John Colvin via Digitalmars-d <digitalmars-d puremagic.com> wrote:Are my fears misplaced?it should not incur any problems. and if such code faults, it's a bug in compiler which must be fixed. if we'll start to use such things, possible bugs will be ironed out.
Sep 26 2014
On Fri, 26 Sep 2014 15:47:15 -0400 Steven Schveighoffer via Digitalmars-d <digitalmars-d puremagic.com> wrote:Thoughts? This can easily be boilerplated in something like roprop!(int, "a")interesting thing. yet i want third arg to roprop. ;-)
Sep 26 2014
On Fri, Sep 26, 2014 at 03:47:15PM -0400, Steven Schveighoffer via Digitalmars-d wrote:I wanted to bring this over from D.learn, because I've never seen this before, and it's an interesting solution to creating a property without much boilerplate. So here it is: class Foo { union { private int _a; // accessible only in this module public const int a; // accessible from anywhere, but read only } }[...] Very clever use of union to mean "this variable has two interpretations: a public, read-only one, and a private, read-write one". I like it! Even ddocs for the const "aspect" of 'a' turn out exactly like a normal member! Does the compiler infer it as safe, though? T -- "No, John. I want formats that are actually useful, rather than over-featured megaliths that address all questions by piling on ridiculous internal links in forms which are hideously over-complex." -- Simon St. Laurent on xml-dev
Sep 26 2014
On 9/26/14 6:32 PM, H. S. Teoh via Digitalmars-d wrote:Does the compiler infer it as safe, though?Hm... good point, I'm not sure if unions are considered safe. But I think that would be a decent enhancement request if not. -Steve
Sep 26 2014
On 9/26/14, 4:32 PM, Steven Schveighoffer wrote:On 9/26/14 6:32 PM, H. S. Teoh via Digitalmars-d wrote:I'd say certain unions may be deemed safe. -- AndreiDoes the compiler infer it as safe, though?Hm... good point, I'm not sure if unions are considered safe. But I think that would be a decent enhancement request if not.
Sep 26 2014
On Fri, Sep 26, 2014 at 05:35:20PM -0700, Andrei Alexandrescu via Digitalmars-d wrote:On 9/26/14, 4:32 PM, Steven Schveighoffer wrote:Hmm. I tried playing with the idea of unions being safe if all members have the same unqualified type, but quickly ran into some nasty cases: union U { void delegate() system sysDg; void delegate() safe safeDg; } Is this union safe or not? Technically, it should be, since there's no possibility of getting an invalid pointer to delegate using U. However, it also breaks safe-ty if you assign U.sysDg and call U.safeDg. (This is currently accepted by the compiler, btw. In safe code.) And what of: union U { immutable int x; int y; } ? This one breaks the type system. It's certainly safe, but has other issues. (The compiler happily accepts this one, BTW.) I think bug reports are in order. :-) There's also the question of what to do with class references: class Base {} class Derived : Base {} union U { Base b; Derived d; // fortunately, the compiler rejects this } I'm sure there are many more such tricky corner cases that people can dream up if they only use their imagination a little. T -- "Maybe" is a strange word. When mom or dad says it it means "yes", but when my big brothers say it it means "no"! -- PJ jr.On 9/26/14 6:32 PM, H. S. Teoh via Digitalmars-d wrote:I'd say certain unions may be deemed safe. -- AndreiDoes the compiler infer it as safe, though?Hm... good point, I'm not sure if unions are considered safe. But I think that would be a decent enhancement request if not.
Sep 26 2014
On Fri, Sep 26, 2014 at 06:20:46PM -0700, H. S. Teoh via Digitalmars-d wrote: [...]union U { void delegate() system sysDg; void delegate() safe safeDg; } Is this union safe or not? Technically, it should be, since there's no possibility of getting an invalid pointer to delegate using U. However, it also breaks safe-ty if you assign U.sysDg and call U.safeDg. (This is currently accepted by the compiler, btw. In safe code.)https://issues.dlang.org/show_bug.cgi?id=13536And what of: union U { immutable int x; int y; } ? This one breaks the type system. It's certainly safe, but has other issues. (The compiler happily accepts this one, BTW.)https://issues.dlang.org/show_bug.cgi?id=13537 T -- It is the quality rather than the quantity that matters. -- Lucius Annaeus Seneca
Sep 26 2014
On Fri, Sep 26, 2014 at 07:32:49PM -0400, Steven Schveighoffer via Digitalmars-d wrote:On 9/26/14 6:32 PM, H. S. Teoh via Digitalmars-d wrote:[...] union U { int* ptr; long i; } void main() safe { U u; u.i = 12345; *u.ptr = 54321; // this can't possibly be safe } How would the compiler decide which union operations are safe and which are not? T -- He who laughs last thinks slowest.Does the compiler infer it as safe, though?Hm... good point, I'm not sure if unions are considered safe. But I think that would be a decent enhancement request if not.
Sep 26 2014
On 9/26/14 8:58 PM, H. S. Teoh via Digitalmars-d wrote:On Fri, Sep 26, 2014 at 07:32:49PM -0400, Steven Schveighoffer via Digitalmars-d wrote:Well, if all unions members are of the same base type, and they only differ by const (and by that I mean, const combined with either mutable or immutable), then it should be safe. So generically, these are safe: union { T t1; const T t2; } union { immutable T t1; const T t2; } This is not: union { T t1; immutable T t2; } checking current rules... looks like safe code doesn't flag unions as unsafe anywhere. I was even able to dereference pointers that were union'd with ints. But really, I think the most useful safe rules would be: 1. A union of any number of non-reference types with the same mutability throughout is safe, even if the type varies. 2. A union of two non-reference types, in which one union member has some bytes defined as mutable, and another union member has those same bytes defined as immutable, is un- safe. Const union members will not disqualify the union. 3. A union of any number of pointer types which point at the same type, but vary only by const, are safe, unless at least one member is mutable and at least one member is immutable. 4. Everything else is un- safe This may break some code, but I think it would define good starting rules to allow this in safe code. -SteveOn 9/26/14 6:32 PM, H. S. Teoh via Digitalmars-d wrote:[...] union U { int* ptr; long i; } void main() safe { U u; u.i = 12345; *u.ptr = 54321; // this can't possibly be safe } How would the compiler decide which union operations are safe and which are not?Does the compiler infer it as safe, though?Hm... good point, I'm not sure if unions are considered safe. But I think that would be a decent enhancement request if not.
Sep 26 2014
On Fri, Sep 26, 2014 at 09:18:28PM -0400, Steven Schveighoffer via Digitalmars-d wrote:On 9/26/14 8:58 PM, H. S. Teoh via Digitalmars-d wrote:[...] Not a bad start. Though I do note that *declaring* an unsafe union (according to the above definitions) is currently allowed in safe code by the compiler, but attempts to access a union member that overlaps with a pointer is rejected. IOW, the compiler doesn't refuse definitions of potentially unsafe unions, as long as you don't actually try to do something unsafe with them. That might make unions more useful (they can be passed around in safe code as long as certain operations are avoided), but probably also trickier to implement correctly. T -- Music critic: "That's an imitation fugue!"On Fri, Sep 26, 2014 at 07:32:49PM -0400, Steven Schveighoffer via Digitalmars-d wrote:Well, if all unions members are of the same base type, and they only differ by const (and by that I mean, const combined with either mutable or immutable), then it should be safe. So generically, these are safe: union { T t1; const T t2; } union { immutable T t1; const T t2; } This is not: union { T t1; immutable T t2; } checking current rules... looks like safe code doesn't flag unions as unsafe anywhere. I was even able to dereference pointers that were union'd with ints. But really, I think the most useful safe rules would be: 1. A union of any number of non-reference types with the same mutability throughout is safe, even if the type varies. 2. A union of two non-reference types, in which one union member has some bytes defined as mutable, and another union member has those same bytes defined as immutable, is un- safe. Const union members will not disqualify the union. 3. A union of any number of pointer types which point at the same type, but vary only by const, are safe, unless at least one member is mutable and at least one member is immutable. 4. Everything else is un- safe This may break some code, but I think it would define good starting rules to allow this in safe code.On 9/26/14 6:32 PM, H. S. Teoh via Digitalmars-d wrote:[...] union U { int* ptr; long i; } void main() safe { U u; u.i = 12345; *u.ptr = 54321; // this can't possibly be safe } How would the compiler decide which union operations are safe and which are not?Does the compiler infer it as safe, though?Hm... good point, I'm not sure if unions are considered safe. But I think that would be a decent enhancement request if not.
Sep 26 2014
On 9/26/14 9:26 PM, H. S. Teoh via Digitalmars-d wrote:Not a bad start. Though I do note that *declaring* an unsafe union (according to the above definitions) is currently allowed in safe code by the compiler, but attempts to access a union member that overlaps with a pointer is rejected.It makes sense that you can declare unsafe unions, because a declaration itself isn't safe, it's only code that is. But my attempts to test this haven't yielded an error. e.g.: class Foo { union { private int _a; public int *a; } void setA(int x) safe { *a = x;} } no complaints...IOW, the compiler doesn't refuse definitions of potentially unsafe unions, as long as you don't actually try to do something unsafe with them. That might make unions more useful (they can be passed around in safe code as long as certain operations are avoided), but probably also trickier to implement correctly.I think it *should* be that way, but I'm not convinced it is yet. -Steve
Sep 26 2014
On Sat, Sep 27, 2014 at 12:43:19AM -0400, Steven Schveighoffer via Digitalmars-d wrote:On 9/26/14 9:26 PM, H. S. Teoh via Digitalmars-d wrote:Argh, looks like another incompletely-implemented part of the compiler: void fun() safe { union U { int p; int* q; } U u; u.p++; // compiles u.q = null; // compiles *u.q++; // x.d(9): Error: field U.q cannot be accessed in safe code because it overlaps with a pointer } While it sorta makes sense in its own way that it's OK to mess around with the union as long as you don't actually try to dereference an overlapped pointer, the error message inspires no confidence that this was actually intentional. :-( On the contrary, it sounds like u.p++ and u.q = null was supposed to be rejected as well, but for some reason aren't.Not a bad start. Though I do note that *declaring* an unsafe union (according to the above definitions) is currently allowed in safe code by the compiler, but attempts to access a union member that overlaps with a pointer is rejected.It makes sense that you can declare unsafe unions, because a declaration itself isn't safe, it's only code that is. But my attempts to test this haven't yielded an error. e.g.: class Foo { union { private int _a; public int *a; } void setA(int x) safe { *a = x;} } no complaints...[...] Apparently I hit jackpot in attempting to try dereferencing an overlapped pointer first. All the other cases seem to be unimplemented! I can't decide whether or not this should be filed as a bug or an enhancement request, because currently we have the paradoxical situation where safe code isn't actually allowed to *dereference* an overlapped pointer, but it *can* stomp all over the pointer by writing garbage to overlapping fields so that system callers can totally screw themselves over when they dereference it! T -- Knowledge is that area of ignorance that we arrange and classify. -- Ambrose BierceIOW, the compiler doesn't refuse definitions of potentially unsafe unions, as long as you don't actually try to do something unsafe with them. That might make unions more useful (they can be passed around in safe code as long as certain operations are avoided), but probably also trickier to implement correctly.I think it *should* be that way, but I'm not convinced it is yet.
Sep 26 2014
"H. S. Teoh via Digitalmars-d" wrote in message news:mailman.1799.1411796077.5783.digitalmars-d puremagic.com...Argh, looks like another incompletely-implemented part of the compiler: void fun() safe { union U { int p; int* q; } U u; u.p++; // compiles u.q = null; // compiles *u.q++; // x.d(9): Error: field U.q cannot be accessed in safe code because > it overlaps with a pointer }This looks perfectly fine to me. Consider if you replaced all uses of the union with multiple variables and explicit casts: int p; int* q; p++; // fine, of course q++; // also fine p = 0; q = null; // both of these are fine, because they don't read anything from the union. // worst case, p was the last value assigned to *(*cast(int**)&p)++; // The cast can't be safe Without unions, you can't create invalid pointers in safe code. With unions, you can, but you can't access them.
Sep 27 2014
On 9/27/14 3:45 AM, Daniel Murphy wrote:"H. S. Teoh via Digitalmars-d" wrote in message news:mailman.1799.1411796077.5783.digitalmars-d puremagic.com...I think that this is equivalent to u.q++, since the ++ does not apply to the pointed-at variable, but at the pointer itself. Weird, my tests showed that this was allowed. More testing, I realize it's because it's a class variable. This code compiles and runs: class Foo { union { int x; int *p; } void foo() safe {*p = 5;} } void main() safe { auto f = new Foo; f.foo(); } Which is similar to this code that does not: void main() safe { union U { int x; int *p; } U u; *u.p = 5; // error }Argh, looks like another incompletely-implemented part of the compiler: void fun() safe { union U { int p; int* q; } U u; u.p++; // compiles u.q = null; // compiles *u.q++; // x.d(9): Error: field U.q cannot be accessed in safe code because > it overlaps with a pointerWithout unions, you can't create invalid pointers in safe code. With unions, you can, but you can't access them.The above shows you can in some situations, but I think that is a bug. -Steve
Sep 27 2014
On 9/26/14, 6:18 PM, Steven Schveighoffer wrote:1. A union of any number of non-reference types with the same mutability throughout is safe, even if the type varies. 2. A union of two non-reference types, in which one union member has some bytes defined as mutable, and another union member has those same bytes defined as immutable, is un- safe. Const union members will not disqualify the union. 3. A union of any number of pointer types which point at the same type, but vary only by const, are safe, unless at least one member is mutable and at least one member is immutable. 4. Everything else is un- safe This may break some code, but I think it would define good starting rules to allow this in safe code.Nice! We need a complete set of rules for this stuff. -- Andrei
Sep 26 2014
On 9/26/14, 5:58 PM, H. S. Teoh via Digitalmars-d wrote:On Fri, Sep 26, 2014 at 07:32:49PM -0400, Steven Schveighoffer via Digitalmars-d wrote:Unions mixing pointers and integrals aren't safe. Those mixing e.g. a float and an int are. -- AndreiOn 9/26/14 6:32 PM, H. S. Teoh via Digitalmars-d wrote:[...] union U { int* ptr; long i; } void main() safe { U u; u.i = 12345; *u.ptr = 54321; // this can't possibly be safe } How would the compiler decide which union operations are safe and which are not?Does the compiler infer it as safe, though?Hm... good point, I'm not sure if unions are considered safe. But I think that would be a decent enhancement request if not.
Sep 26 2014
On Friday, 26 September 2014 at 19:47:15 UTC, Steven Schveighoffer wrote:I wanted to bring this over from D.learn, because I've never seen this before, and it's an interesting solution to creating a property without much boilerplate. So here it is: class Foo { union { private int _a; // accessible only in this module public const int a; // accessible from anywhere, but read only } } And it works now, probably has for a while. Thoughts? This can easily be boilerplated in something like roprop!(int, "a") I am really not sure what union does to compiler optimization or runtime concerns, if it has any significant drawbacks. From what I can tell, it's a valid solution. Credit to Mark Schütz for the idea. -SteveThis is a clever syntax, but I can't say I particularly care for it since it aliases two names for the same location which differ only in their visibility, and this feels... wrong to me somehow. syntax allows for it directly: class Foo { int A { get; private set; } } The compiler automatically creates a (hidden) backing property (this is an implementation detail of course), both internal and external customers use the same name, and there is no redundancy. analog would preserve A's access methods and handling as if it were a field if that was the user's wish. That's my $0.02.
Sep 26 2014
On Friday, 26 September 2014 at 22:58:53 UTC, Cliff wrote:This is a clever syntax, but I can't say I particularly care for it since it aliases two names for the same location which differ only in their visibility, and this feels... wrong to me somehow. syntax allows for it directly: class Foo { int A { get; private set; } } The compiler automatically creates a (hidden) backing property (this is an implementation detail of course), both internal and external customers use the same name, and there is no redundancy. - a D analog would preserve A's access methods and handling as if it were a field if that was the user's wish. That's my $0.02.in D for a long time. Using a mixin is just plain ugly and breaks tooling, yet this is such a common thing to have to do. It is quite disappointing that there's no shorthand for it, like ' property int a;' or ' property(readonly) int b'. (On that matter, I'm not a fan in general of properties being various methods glued together by an property, but that's set in stone by now.)
Sep 26 2014
On Friday, 26 September 2014 at 19:47:15 UTC, Steven Schveighoffer wrote:I wanted to bring this over from D.learn, because I've never seen this before, and it's an interesting solution to creating a property without much boilerplate. So here it is: class Foo { union { private int _a; // accessible only in this module public const int a; // accessible from anywhere, but read only } } And it works now, probably has for a while. Thoughts? This can easily be boilerplated in something like roprop!(int, "a") I am really not sure what union does to compiler optimization or runtime concerns, if it has any significant drawbacks. From what I can tell, it's a valid solution. Credit to Mark Schütz for the idea. -SteveThanks, I love this! There is actually a very important ABI difference, in all other "property" implementations in other languages(of which I'm aware), the ABI is changed to be a method rather than a member, for this reason I think we shouldn't refer to this feature as a "property", maybe "field/member" is more appropriate? Both properties and "access restricted fields" has their place depending on what one is trying to accomplish, but in most cases I find myself wanting this very feature and not normal properties. I couldn't resist trying this in C++, clang rejected it outright, GCC let it through with a warning.
Sep 26 2014