December 13, 2011
On 12/14/2011 12:14 AM, Peter Alexander wrote:
> On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
>> On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
>>> There's a phrase in Romanian that quite applies: "From the lake into
>>> the well".
>>
>> I believe the English version is "Out of the frying pan, into the
>> fire" :)
>>
>> Inconsequential space-filler opinion: I am OK with @property, mainly
>> because it's a common feature among PLs, it's better than nothing, and
>> don't know better solutions.
>
> In my opinion, it's not better than nothing.
>
> What it gives you:
>
> 1. A bit of syntactic sugar.
> 2. The ability to refactor member look up easily.
>
> What it costs:
>
> 1. Overloads syntax.
> a. obj.field can now be an arbitrary function call.
> b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.

> 2. Complicating the language (proof: this discussion)
> 3. Another thing to learn.
> 4. Another thing for tools to process.
>
>
> I don't think the syntax sugar it provides counts for anything really.
>
> The ability to refactor member look ups is nice, but I find that this
> rarely occurs in practice and even when it occurs, it's not hard to
> replace obj.field with obj.field() or obj.getField().
>
> The costs far outweigh the benefits IMO.

December 13, 2011
On 13/12/11 11:11 PM, Timon Gehr wrote:
> On 12/14/2011 12:14 AM, Peter Alexander wrote:
>> On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
>>> On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
>>>> There's a phrase in Romanian that quite applies: "From the lake into
>>>> the well".
>>>
>>> I believe the English version is "Out of the frying pan, into the
>>> fire" :)
>>>
>>> Inconsequential space-filler opinion: I am OK with @property, mainly
>>> because it's a common feature among PLs, it's better than nothing, and
>>> don't know better solutions.
>>
>> In my opinion, it's not better than nothing.
>>
>> What it gives you:
>>
>> 1. A bit of syntactic sugar.
>> 2. The ability to refactor member look up easily.
>>
>> What it costs:
>>
>> 1. Overloads syntax.
>> a. obj.field can now be an arbitrary function call.
>> b. May have arbitrary cost (e.g. T[].length)
>
> ??? T[].length is a field access, not a property function. It takes a
> small constant amount of time.

Assigning to the length of an array may reallocate it, which is not a small, nor constant amount of time.

int[] a;
...
a.length = n; // may invoke a GC allocation + O(n) memcpy
December 14, 2011
On Sunday, December 11, 2011 02:05:08 Andrei Alexandrescu wrote:
> On 12/11/11 1:30 AM, Jonathan M Davis wrote:
> > On Sunday, December 11, 2011 01:16:28 Andrei Alexandrescu wrote:
> >> To truly confer user-defined types the same capability, we should
> >> define
> >> opPassByValue() which is implicitly invoked whenever an object is
> >> passed
> >> by value into a function. By default that is a do-nothing operator;
> >> for
> >> arrays it would do the cast thing (or, equivalently, invoke "[]" on
> >> the
> >> array), and people could define it to do whatever. We could do all
> >> that.
> >> The question is, is the added complexity justified?
> > 
> > I think that it's completely justified. We need a way to define tail-constness for ranges. Given const's transitiveness, it's very easy to end up in a situation where you have a const range, and having a means to get a tail-const version of that range would be very valuable. I don't know if opPassByValue is the best solution, but if not, we at least need a similar one.
> 
> I'm not sure. How many times have you been in a place in life where you had a const range on your hands, that's not an array? I haven't.

I tend to avoid const ranges precisely because they pretty much never work. I'd use them more if a tail-const version of them were easily obtainable - _especially_ if they worked the same way that arrays are going to be working with IFTI. Also, as std.container is filled out, the number of ranges which aren't arrays will definitely increase. Right now, they're almost always arrays or arrays wrapped by other ranges, and often you have to call array on the wrapped ones anyway, so a large portion of the time at this point, ranges are arrays. And while that will still hold to some extent, that should lessen as std.container is fleshed out. And that means that issues with const ranges will increase.

Also, it's completely inconsistent that you can pass a const array to a range- based function and have it work but not a const user-defined range. It may be that we could get the compiler to figure it out based on slicing (assuming that opSlice returns the same type as the range itself aside from constness - otherwise passing containers to range-based functions would instantiate on the containers, which would cause issues, especially since it would be the container being passed, not a slice). And if we could do that, then I don't think that there would be any need for opPassByValue, but without a solution along those lines, we're going to have people complaining about not being able to pass const value-type ranges to range-based functions. And as fantastic as template constraints are, they don't make it immediately obvious why the type failed - certainly nothing as nice as "Error: find does not work with a const range."

I do think that there is merit in seeing whether we can get the compiler to use opSlice to do what opPassByValue would do, but I also think that we should do something about this issue, or const ranges will forever be a problem. The only reasons that I don't run into the issue more is because I avoid const with ranges and with such a sparse std.container, so many ranges are arrays.

- Jonathan M Davis
December 14, 2011
On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:

> We could have inferred property intention from the code pattern, without requiring any keyword. That solution (which was discussed and rejected in this newsgroup) was miles ahead from the drivel of @property we have now.

By "code patterns", you mean something like this?

	struct Foo
	{
		int getBar();
		void setBar(int);
	}

	void main()
	{
		Foo foo;
		int a = foo.bar;  // calls getBar()
		foo.bar = a;      // calls setBar(a)
	}

I agree it's better. For one thing it'd be much less confusing about whether it make sense to make something a property or not because you'd have to write "get" in front of it -- for instance getSave doesn't make any sense.

And it'd be much less problematic too: the way @property is currently designed, you can't distinguish between a definition for a an array-member property getter and a module-level property setter. Also with the current design you have no way to disambiguate array-member properties with the same name coming from different modules -- can't replace array.front with std.range.front(array) when @property is enforced -- having access to the @property's underlying function would mitigate this -- std.range.getFront(array) would still work. The above code pattern would also make it saner to take the address of the getter function as a separate thing from taking the address of a ref value obtained from a property.

Personally, I'm skeptical the current property design can work as intended without introducing many issues like the above. I think perhaps the biggest mistake was to not implement it fully from the start at a time where we could easily revert to another proposition if it proved to be problematic. Unfortunately, now we're stuck with @property and all its problems… although I'd sure like the design to be revised.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

December 14, 2011
On Tuesday, December 13, 2011 21:36:43 Michel Fortin wrote:
> On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu
> 
> <SeeWebsiteForEmail@erdani.org> said:
> > We could have inferred property intention from the code pattern, without requiring any keyword. That solution (which was discussed and rejected in this newsgroup) was miles ahead from the drivel of @property we have now.
> 
> By "code patterns", you mean something like this?
> 
> 	struct Foo
> 	{
> 		int getBar();
> 		void setBar(int);
> 	}
> 
> 	void main()
> 	{
> 		Foo foo;
> 		int a = foo.bar;  // calls getBar()
> 		foo.bar = a;      // calls setBar(a)
> 	}
> 
> I agree it's better. For one thing it'd be much less confusing about whether it make sense to make something a property or not because you'd have to write "get" in front of it -- for instance getSave doesn't make any sense.
> 
> And it'd be much less problematic too: the way @property is currently designed, you can't distinguish between a definition for a an array-member property getter and a module-level property setter. Also with the current design you have no way to disambiguate array-member properties with the same name coming from different modules -- can't replace array.front with std.range.front(array) when @property is enforced -- having access to the @property's underlying function would mitigate this -- std.range.getFront(array) would still work. The above code pattern would also make it saner to take the address of the getter function as a separate thing from taking the address of a ref value obtained from a property.
> 
> Personally, I'm skeptical the current property design can work as
> intended without introducing many issues like the above. I think
> perhaps the biggest mistake was to not implement it fully from the
> start at a time where we could easily revert to another proposition if
> it proved to be problematic. Unfortunately, now we're stuck with
> @property and all its problems… although I'd sure like the design to be
> revised.

I'd think that some revision would be possible even if it breaks code as long as there is great need for it - though that would depend on Walter's decision. But since @property is in TDPL, a complete redesign wouldn't make sense without _major_ need. Smaller tweaks wouldn't be as big a deal though. I'm not quite sure how @property would be adjusted for some of these corner cases though. The basic idea works well for member functions, but once you add free functions into the mix, it gets more complicated.

- Jonathan M Davis
December 14, 2011
On 12/14/2011 12:35 AM, Peter Alexander wrote:
> On 13/12/11 11:11 PM, Timon Gehr wrote:
>> On 12/14/2011 12:14 AM, Peter Alexander wrote:
>>> On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
>>>> On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu
>>>> wrote:
>>>>> There's a phrase in Romanian that quite applies: "From the lake into
>>>>> the well".
>>>>
>>>> I believe the English version is "Out of the frying pan, into the
>>>> fire" :)
>>>>
>>>> Inconsequential space-filler opinion: I am OK with @property, mainly
>>>> because it's a common feature among PLs, it's better than nothing, and
>>>> don't know better solutions.
>>>
>>> In my opinion, it's not better than nothing.
>>>
>>> What it gives you:
>>>
>>> 1. A bit of syntactic sugar.
>>> 2. The ability to refactor member look up easily.
>>>
>>> What it costs:
>>>
>>> 1. Overloads syntax.
>>> a. obj.field can now be an arbitrary function call.
>>> b. May have arbitrary cost (e.g. T[].length)
>>
>> ??? T[].length is a field access, not a property function. It takes a
>> small constant amount of time.
>
> Assigning to the length of an array may reallocate it, which is not a
> small, nor constant amount of time.
>
> int[] a;
> ...
> a.length = n; // may invoke a GC allocation + O(n) memcpy

OK, I see, thanks. I don't think it is problematic in this particular case though.

December 14, 2011
On 13.12.2011 23:17, Vladimir Panteleev wrote:
> On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
>> There's a phrase in Romanian that quite applies: "From the lake into
>> the well".
>
> I believe the English version is "Out of the frying pan, into the fire" :)

The Norwegian version is "From ashes to fire" (direct translation) or "From the ashes into the fire"
December 14, 2011
Jonathan M Davis:

> I tend to avoid const ranges precisely because they pretty much never work. I'd use them more if a tail-const version of them were easily obtainable -

This is what I was trying to answer to Andrei :-)

Bye,
bearophile
December 14, 2011
On Wed, 14 Dec 2011 02:36:43 -0000, Michel Fortin <michel.fortin@michelf.com> wrote:

> On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
>
>> We could have inferred property intention from the code pattern, without requiring any keyword. That solution (which was discussed and rejected in this newsgroup) was miles ahead from the drivel of @property we have now.
>
> By "code patterns", you mean something like this?
>
> 	struct Foo
> 	{
> 		int getBar();
> 		void setBar(int);
> 	}
>
> 	void main()
> 	{
> 		Foo foo;
> 		int a = foo.bar;  // calls getBar()
> 		foo.bar = a;      // calls setBar(a)
> 	}

Why not something similar to C# syntax...

struct Foo
{
  int bar		// <- does DMD do lookahead?  detect { instead of ; here and trigger "property" parsing
  {
    get
    {
      return value;  // <- 'value' meaning the value of the 'bar' member
    }
    set
    {
      this = value; // <- 'this' meaning the 'bar' member, 'value' meaning the RHS of the "£instance.bar = <value>" statement
    }
  }
}

Regan
December 14, 2011
On Wed, 14 Dec 2011 13:27:57 -0000, Regan Heath <regan@netmail.co.nz> wrote:

> On Wed, 14 Dec 2011 02:36:43 -0000, Michel Fortin <michel.fortin@michelf.com> wrote:
>
>> On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
>>
>>> We could have inferred property intention from the code pattern, without requiring any keyword. That solution (which was discussed and rejected in this newsgroup) was miles ahead from the drivel of @property we have now.
>>
>> By "code patterns", you mean something like this?
>>
>> 	struct Foo
>> 	{
>> 		int getBar();
>> 		void setBar(int);
>> 	}
>>
>> 	void main()
>> 	{
>> 		Foo foo;
>> 		int a = foo.bar;  // calls getBar()
>> 		foo.bar = a;      // calls setBar(a)
>> 	}
>
> Why not something similar to C# syntax...
>
> struct Foo
> {
>    int bar		// <- does DMD do lookahead?  detect { instead of ; here and trigger "property" parsing
>    {
>      get
>      {
>        return this;  // <- 'this' meaning the 'bar' member
>      }
>      set
>      {
>        this = value; // <- 'this' meaning the 'bar' member, 'value' meaning the RHS of the "£instance.bar = <value>" statement
>      }
>    }
> }
>
> Regan

Apologies, there was a typo/mistake in the 'get' above. :)

Regan

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/