September 08, 2016
On Wednesday, 7 September 2016 at 09:34:12 UTC, Jonathan M Davis wrote:
> But if you return the value by ref, then you pretty much circumvent all of that, because then someone can do something like take the address of the return value and procede to mutate it whenever they want without hitting your breakpoint or log messages or any of that. You can do a few things that can't be done with a public member variable, but on the whole, returning by ref defeats the purpose of having a property function.

No, manipulation of the value can be only done after accessing it through the property, thus its mission is fulfilled.

> So, while some @property functions may return by ref, most won't, and it's arguably a bad idea in general.

It's good when it allows easy refactoring.

> Stuff like assignment can be made to work, but something as simple as passing by ref falls simply cannot be done except in the case where the @property function returns by ref

True.

> And for a large percentage of property functions, you don't want it to be the case that taking the address of the property function gives you a pointer to a member variable.

It depends.

> Anything that would require an actual variable with an actual memory location isn't going to work unless the @property function returns by ref, and making taking the address of that kind of @property function give you the address of the variable would then not be consistent with any other @property function, which would create a different set of problems.

Properties are meant to be inconsistent, i.e. to have different implementations.

> It's nice that we can have property syntax rather than having to have functions that start with get and set, but it really doesn't work to fully emulate variables.

What you said is more like your preference to not pass values by ref. If you don't want it, don't do it, no problem.
September 11, 2016
On Tuesday, 6 September 2016 at 19:37:26 UTC, Jonathan M Davis wrote:
> On Tuesday, September 06, 2016 19:18:11 John via Digitalmars-d wrote:
>> Currently it seems that @property isn't implemented correctly. For some reason when you try to get the pointer of a property it returns a delegate for some reason. This just seems plain wrong, the whole purpose of a property is for a function to behave as if it weren't a function. There's also some inconsistencies in the behavior, "get" is implemented one way and then "set" is implemented another.
>>
>> http://ideone.com/ZgGT2G
>>
>>      &t.x         // returns "ref int delegate()"
>>      &t.x()       // ok returns "int*", but defeats purpose of
>> @property
>>      &(t.j = 10)  // shouldn't this return "ref int delegate(int)"
>> ?
>>
>> It would be nice to get this behavior fixed, so that it doesn't become set in stone. I think returning a delegate pointer is not what people would except nor is there really any use case for it.
>
> Okay. How would it work to safely get a pointer to anything but the @property function when taking its address? &t.x() is just going to give you the address of the return value - which in most cases, is going to be a temporary, so if that even compiles in most cases, it's a bit scary. Sure, if the @property function returns by ref, then it can work, but an @property function which returns by ref isn't worth much, since you're then giving direct access to the member variable which is what an @property function is usually meant to avoid. If you wanted to do that, you could just use a public member variable.
>
> So, given that most @property functions are not going to return by ref, how does it make any sense at all for taking the address of an @property function to do anything different than give you a delegate? Sure, that's not what happens when you take the address of a variable, but you're not dealing with a variable. You're dealing with an @property function which is just trying to emulate a variable.
>
> The reality of the matter is that an @property function is _not_ a variable. It's just trying to emulate one, and that abstraction falls apart _really_ fast once you try and do much beyond getting and setting the value - e.g. passing by ref falls flat on its face. We could do better than currently do (e.g. making += lower to code that uses both the getter and the setter when the getter doesn't return by ref), but there are some areas where a property function simply can't act like a variable, because it isn't one. There isn't even a guarantee that an @property function is backed by memory. It could be a completely calculated value, in which case, expecting to get an address of a variable when taking the address of the @property function makes even less sense.
>
> - Jonathan M Davis

I don't see how that would be a problem, you can't take the address of an rvalue... The problem you describe would be true for functions as well. What's not true is that it is compilable (see: http://ideone.com/MXhkXC ). Any problem you can conjure up about references, temporary values and pointers, all of that would be true for a regular function as well.

Obviously it is not a variable, but if you use a function and it returns a reference and you take the address of it. What you get is the address of the returned value not of the function. int v = obj.prop; if you look at that "prop" is a called function pretending to be a variable. If you take the address of a called function, you get the address of the returned variable, not the function. If you take the address of a variable, you get the address of the variable.

On Wednesday, 7 September 2016 at 07:44:05 UTC, Ethan Watson wrote:
> On Tuesday, 6 September 2016 at 19:18:11 UTC, John wrote:
>> It would be nice to get this behavior fixed.
>
> Disagree. I've used properties before in C# to transform to and from data sets required for network multiplayer. It works functionally the same way in D. Behaviour is as I would expect for the wider implications of how properties can work.

You can't really take one sentence out of context, I didn't say it in the sense that it was completely broken to the point of being useless. The part I'm asking to be changed, you probably didn't even ever use. C# is a managed language, I don't think you can even take the pointer of anything unless you enable the unsafe switch.


On Tuesday, 6 September 2016 at 19:34:59 UTC, ag0aep6g wrote:
> On 09/06/2016 09:18 PM, John wrote:
>>     &(t.j = 10)  // shouldn't this return "ref int delegate(int)" ?
>
> `&t.j` should and does. With `= 10`, it's definitely a call, just like `&t.x()`.
>
>> It would be nice to get this behavior fixed, so that it doesn't become
>> set in stone.
>
> Unfortunately, it already kinda is. Just flipping the switch would break circa all D code in existence. That's deemed unacceptable by the leadership, as far as I know.

Don't really see that to be true. I don't see any use case for taking the address of the delegate for a property. Wouldn't be surprised if it only broke 1% of code out there. I mean it's probably used so little that it isn't even properly implemented. You can get the getter property delegate, but you can't get the setter property delegate. Either way it's broken as it is now.

September 11, 2016
On Sunday, 11 September 2016 at 07:19:54 UTC, John wrote:
> You can't really take one sentence out of context, I didn't say it in the sense that it was completely broken to the point of being useless.

There's nothing out of context about it. Would it have made you feel better had I quoted your entire message knowing that I wouldn't have changed a word of the response?


But if that's how you want to play.

> The part I'm asking to be changed, you probably didn't even ever use. C# is a managed language, I don't think you can even take the pointer of anything unless you enable the unsafe switch.

You're not showing a good grasp at all as to what a property is. In C# and in D, a property has *never* guaranteed the existence of a variable. In both cases, they allow syntactic sugar for letting the getter/setter pattern established by C++ look like variables.

This is important.

No, really.

Take std.bitmanip for an example of what I was talking about. It autogenerates properties for a bitfield. The types each property returns and lets you set are not at all indicative of the datatype underneath as it's literally just a bunch of bits. The property functions transform the data types given/return to/from a bitfield. What exactly do you suggest &property return if it was to return a char starting at bit 13 of a bitfield?

But we can go one further. __traits( allMembers, Type ) and __traits( getMember, Type ). Let's say you're writing an auto-serialisation library (or take std.json as an example). Assuming a property is a stand-in for another variable then what happens there when you're checking for the type of a member is the delegate type, and later on you'll get the actual variable. Now change it so that the type of a property returns the actual type. Now you're serialising a piece of data twice.

But what if our @property function increments another variable inside a class whenever you access it? That's pretty dangerous if you start treating the property as an actual type instead of a function/delegate.

Thus, your example:

    &t.x         // returns "ref int delegate()"
    &t.x()       // ok returns "int*", but defeats purpose of @property
    &(t.j = 10)  // shouldn't this return "ref int delegate(int)" ?

First one I'd expect. Second one I'd expect. Third one I'd expect results in int*. You're getting the address of the results of the assign operation. Look at it this way: int val = (t.j = 10); You'd expect val and t.j to be 10, right? So why do you expect to get a ref int delegate(int) just because you ask for the address of it?

Like I said. Disagree. There's nothing that needs fixing here.
September 12, 2016
On 11.09.2016 14:02, Ethan Watson wrote:
> On Sunday, 11 September 2016 at 07:19:54 UTC, John wrote:
>> ...
>> The part I'm asking to be changed, you probably didn't even ever use.
>> C# is a managed language, I don't think you can even take the pointer
>> of anything unless you enable the unsafe switch.
>
> ... In C#
> and in D, a property has *never* guaranteed the existence of a variable.
> In both cases, they allow syntactic sugar for letting the getter/setter
> pattern established by C++ look like variables.
> ...

His property returns by ref.


> ...
>
> Take std.bitmanip for an example of what I was talking about. It
> autogenerates properties for a bitfield. The types each property returns
> and lets you set are not at all indicative of the datatype underneath as
> it's literally just a bunch of bits. The property functions transform
> the data types given/return to/from a bitfield. What exactly do you
> suggest &property return if it was to return a char starting at bit 13
> of a bitfield?
> ...

Not a delegate. In a sane world, it would give you a compile error because 'property' is an rvalue.


> But we can go one further. __traits( allMembers, Type ) and __traits(
> getMember, Type ). Let's say you're writing an auto-serialisation
> library (or take std.json as an example). Assuming a property is a
> stand-in for another variable then what happens there when you're
> checking for the type of a member is the delegate type, and later on
> you'll get the actual variable. Now change it so that the type of a
> property returns the actual type. Now you're serialising a piece of data
> twice.
> ...

You do realize that typeof(property) is the type of the return value, right? Also, it's easy. Add __traits(isVariable,...) or __traits(isProperty,...), or just use .tupleof. Furthermore you can even get the property accessor function overload set using (a hypothetical) __traits(getPropertyAccessors,...).

> But what if our @property function increments another variable inside a
> class whenever you access it? That's pretty dangerous if you start
> treating the property as an actual type instead of a function/delegate.
>
> Thus, your example:
>
>     &t.x         // returns "ref int delegate()"
>     &t.x()       // ok returns "int*", but defeats purpose of @property
>     &(t.j = 10)  // shouldn't this return "ref int delegate(int)" ?
>
> First one I'd expect.

Why? It's awful.

> Second one I'd expect.

No, even more awful. typeof(t.x) is 'int'. You are not even supposed to be able to call an 'int'. The second one should be a compile error: "Error: function expected before (), not t.x of type int"

> Third one I'd expect results in int*.

Agreed, that one is sane.
September 12, 2016
On Sunday, 11 September 2016 at 23:31:54 UTC, Timon Gehr wrote:
> His property returns by ref.

Irrelevant for the implementation details of properties. Ref in that context specifies a function property that makes the property function return by ref (wrap your head around that one). That entire post went in to detail about why treating properties as the functions they are is correct.

> You do realize that typeof(property) is the type of the return value, right? Also, it's easy. Add __traits(isVariable,...) or __traits(isProperty,...), or just use .tupleof. Furthermore you can even get the property accessor function overload set using (a hypothetical) __traits(getPropertyAccessors,...).

You are correct. typeof( __traits( getMember, Type, PropertyName ) ) is the type of the return type of the function, since getMember forms a complete expression which evaluates down to the return type.

Note that all of the __traits( is<X>Function ) return true correctly on these things though. This is one of the checks I have to make when parsing over a class to correctly determine what is and isn't actually a variable. I've even wrapped it all up in a trait called IsVariable. The std library has traits for checking types but nothing that straight up tells you if something is a variable or not.

As such, who needs __traits( getPropertyAccessors ) when __traits( getOverloads ) already works?

> [Commentary on example]

Actually, I take back what I said. Mostly because of typeof( t.x ). The thing that needs fixing is the property evaluation order so that ambiguities like all of this don't exist.
September 12, 2016
On Sunday, 11 September 2016 at 12:02:29 UTC, Ethan Watson wrote:
> But what if our @property function increments another variable inside a class whenever you access it? That's pretty dangerous if you start treating the property as an actual type instead of a function/delegate.

You mean your serialization library will break if @property changes behavior?
September 12, 2016
On Monday, 12 September 2016 at 09:25:40 UTC, Kagamin wrote:
> You mean your serialization library will break if @property changes behavior?

Any serialisation library can break if a property is indistinguishable from an ordinary type, as a property is explicitly code that returns a value and faces all the allowances and restrictions that normal functions have.

In my case, it will break if this template fails:

template IsVariable( X... ) if ( X.length == 1 )
{
  static if( is( X[ 0 ] == void ) || is( typeof( X[ 0 ] ) == void ) )
  {
    enum IsVariable = false;
  }
  else static if ( !IsSomeType!( X[ 0 ] ) )
  {
    static if( isSomeFunction!( X[ 0 ] ) )
    {
      enum IsVariable = isFunctionPointer!( X[ 0 ] ) || isDelegate!( X[ 0 ] );
    }
    else
    {
      enum IsVariable = is( typeof( X [ 0 ] ) )
              && !is( typeof( X [ 0 ] ) == void )
              && IsMutable!( typeof( X[ 0 ] ) );
    }
  }
  else
  {
    enum IsVariable = false;
  }
}
September 12, 2016
Your template will not change behavior if isSomeFunction returns true for properties. That's probably ok.
September 12, 2016
On Tuesday, 6 September 2016 at 19:18:11 UTC, John wrote:

This is all you need to know:

https://wiki.dlang.org/Property_Discussion_Wrap-up
September 16, 2016
On Sunday, 11 September 2016 at 12:02:29 UTC, Ethan Watson wrote:
> On Sunday, 11 September 2016 at 07:19:54 UTC, John wrote:
>> You can't really take one sentence out of context, I didn't say it in the sense that it was completely broken to the point of being useless.
>
> There's nothing out of context about it. Would it have made you feel better had I quoted your entire message knowing that I wouldn't have changed a word of the response?
>
>
> But if that's how you want to play.
>

Your comment was out of place, saying properties don't need to be changed is like saying @property shouldn't even be a D feature cause you can create the same functional program in C++, which does not have the property feature. You also made a reference to C#, which doesn't even allow you take address of So I don't know what you mean by that's how I want to play, when you instigated said argument.

>> The part I'm asking to be changed, you probably didn't even ever use. C# is a managed language, I don't think you can even take the pointer of anything unless you enable the unsafe switch.
>
> You're not showing a good grasp at all as to what a property is. In C# and in D, a property has *never* guaranteed the existence of a variable. In both cases, they allow syntactic sugar for letting the getter/setter pattern established by C++ look like variables.
>
> This is important.
>
> No, really.
>
> Take std.bitmanip for an example of what I was talking about. It autogenerates properties for a bitfield. The types each property returns and lets you set are not at all indicative of the datatype underneath as it's literally just a bunch of bits. The property functions transform the data types given/return to/from a bitfield. What exactly do you suggest &property return if it was to return a char starting at bit 13 of a bitfield?

It's not really that important. What it allows is returning references. You can make a comparison to any other language that has properties it doesn't really matter. This is how D was implemented. If they wanted to be like every other language then it shouldn't have been allowed to even return a reference. But it is does, that's how it's implemented and odds are it probably won't change now to not allow it. D also has the "&" implemented, what I am discussing is whether it was implemented correctly or not. Honestly it is no implemented correctly. To the point I would actually rather they remove the functionality so that you can't take the address of a property. If they are not willing to change it to function in a different way.

This has been brought up by someone else. I honestly don't understand why it's such a hard concept. Maybe you don't come from C++ and thus don't use a language that provides a way to take the address of things. That's why it keeps being brought up. Anyways a bitfield can't actually represent a single, there's no type for a bit. The smallest type is a byte, which is 8 bits. So even if it wasn't a property there's no way you can take the address of a bit. So that's the first issue, you are trying to use an example that doesn't make sense even outside the concept of properties. The second issue is, this is defined behavior. You can't take the address of a rvalue, there's an ideone link in my previous post show this if you missed it. So taking the address of a property would return an error if it didn't return a reference.


> But we can go one further. __traits( allMembers, Type ) and __traits( getMember, Type ). Let's say you're writing an auto-serialisation library (or take std.json as an example). Assuming a property is a stand-in for another variable then what happens there when you're checking for the type of a member is the delegate type, and later on you'll get the actual variable. Now change it so that the type of a property returns the actual type. Now you're serialising a piece of data twice.
>
> But what if our @property function increments another variable inside a class whenever you access it? That's pretty dangerous if you start treating the property as an actual type instead of a function/delegate.

Well that's how it is currently implemented actually.

    struct S
    {
        @property int prop() { return 0; }
    }

    writeln(typeof(S.prop).stringof) // prints "int", not "delegate"

I'm only talking about taking the address of a property. That does no way infer that there shouldn't be some way to identify that it is a property at compile time. The way you should check if a member is a property shouldn't be by taking the address of it. That's not as clear as having a trait or other implementation such that you could do "isProperty". That is much more clearer. If the only way to identify a property is by checking the typeof() a member for when you take it's address, then that's a hack and a better way to identify a property should be implemented.

> Thus, your example:
>
>     &t.x         // returns "ref int delegate()"
>     &t.x()       // ok returns "int*", but defeats purpose of @property
>     &(t.j = 10)  // shouldn't this return "ref int delegate(int)" ?
>
> First one I'd expect. Second one I'd expect. Third one I'd expect results in int*. You're getting the address of the results of the assign operation. Look at it this way: int val = (t.j = 10); You'd expect val and t.j to be 10, right? So why do you expect to get a ref int delegate(int) just because you ask for the address of it?

Well I put that there more satirically, as as far as I am aware there is no way to get the delegate for the setter. Getting the delegate from t.x would make as much sense as it does for that setter function.