December 29, 2010
On 12/27/10 6:55 PM, Andrei Alexandrescu wrote:
> On 12/27/10 12:35 PM, bearophile wrote:
>> Through Reddit I have found a link to some information about the Clay
>> language, it wants to be (or it will be) a C++-class language, but
>> it's not tied to C syntax. It shares several semantic similarities
>> with D too. It looks like a cute language:
>> https://github.com/jckarter/clay/wiki/
> [snip]
>
> FWIW I just posted a response to a question asking for a comparison
> between Clay and D2.
>
> http://www.reddit.com/r/programming/comments/es2jx/clay_programming_language_wiki/

That thread is shaping up more and more interesting because it's turning into a discussion of generic programming at large.

Andrei
December 29, 2010
On Wed, 29 Dec 2010 19:24:12 +0100
Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:

> But I really don't see the benefit of changing the semantics of import. You won't get shot in the foot since D offers good protection from function hijacking.

Yes, I'm aware of this. But this (great) feature is not related to the discussion, I guess.

> But even if you did change the semantics of import to a static import, you still wouldn't fix the *programmers* themselves. Everyone will simply start using /import module.*/, or /import module.all/ instead of using the safe default /import module/ which would be a static import. No defined default or convention in the community can force programmers to code in one way.
> 
> And if you doubt that, just take a look at all the Python code that's out there. A ton of programmers still use the star syntax to import every symbol into the current scope, even though its frowned upon by the Python community (and afaik you can't use it anymore in Python 3). But D has counter-measures which prevent hijacking, and hence it's pretty safe to simply import the whole module without worrying too much.

We certainly don't read code by the same programmers ;-) I have never seen "from x import *" except in newcomer code and case like evoked in a previous post, namely parsing: a parser-definition module using eg "from pyparsing import *".
A counter measure is to define what is to be exported. (A very nice feature of Lua: th module's return {whatever you want to export}). Similarly in python you get __all__ (some proposed to allow import * only id the module defines __all__, sensible indeed).
In D you have to define everything _else_ in the module private: not only it's not the default, it's imo reversing the logic.
[Now, i'll stop arguing ;-)]

Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com

December 29, 2010
On Wed, 29 Dec 2010 14:42:53 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 12/27/10 6:55 PM, Andrei Alexandrescu wrote:
>> On 12/27/10 12:35 PM, bearophile wrote:
>>> Through Reddit I have found a link to some information about the Clay
>>> language, it wants to be (or it will be) a C++-class language, but
>>> it's not tied to C syntax. It shares several semantic similarities
>>> with D too. It looks like a cute language:
>>> https://github.com/jckarter/clay/wiki/
>> [snip]
>>
>> FWIW I just posted a response to a question asking for a comparison
>> between Clay and D2.
>>
>> http://www.reddit.com/r/programming/comments/es2jx/clay_programming_language_wiki/
>
> That thread is shaping up more and more interesting because it's turning into a discussion of generic programming at large.

I wanted to address your post in the reddit discussion regarding the issue of operator overloads not being virtual:

"This non-issue has been discussed in the D newsgroup. You can implement virtuals on top of non-virtuals efficiently, but not vice versa."

I've found some very real problems with that, when implementing operator overloads in dcollections.  It's forced me to use the (yet to be deprecated) opXXX forms.  Specifically, you cannot use covariance with templated functions without repeating the entire implementation in the derived class.  Also, let's not forget, templates can't be used in interfaces, which means no operator overloading in interfaces.

Related bug:

http://d.puremagic.com/issues/show_bug.cgi?id=4174

-Steve
December 29, 2010
On 12/29/10 2:10 PM, Steven Schveighoffer wrote:
> On Wed, 29 Dec 2010 14:42:53 -0500, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> On 12/27/10 6:55 PM, Andrei Alexandrescu wrote:
>>> On 12/27/10 12:35 PM, bearophile wrote:
>>>> Through Reddit I have found a link to some information about the Clay
>>>> language, it wants to be (or it will be) a C++-class language, but
>>>> it's not tied to C syntax. It shares several semantic similarities
>>>> with D too. It looks like a cute language:
>>>> https://github.com/jckarter/clay/wiki/
>>> [snip]
>>>
>>> FWIW I just posted a response to a question asking for a comparison
>>> between Clay and D2.
>>>
>>> http://www.reddit.com/r/programming/comments/es2jx/clay_programming_language_wiki/
>>>
>>
>> That thread is shaping up more and more interesting because it's
>> turning into a discussion of generic programming at large.
>
> I wanted to address your post in the reddit discussion regarding the
> issue of operator overloads not being virtual:
>
> "This non-issue has been discussed in the D newsgroup. You can implement
> virtuals on top of non-virtuals efficiently, but not vice versa."
>
> I've found some very real problems with that, when implementing operator
> overloads in dcollections. It's forced me to use the (yet to be
> deprecated) opXXX forms. Specifically, you cannot use covariance with
> templated functions without repeating the entire implementation in the
> derived class.

Glad you're bringing that up. Could you please post an example that summarizes the issue?

> Also, let's not forget, templates can't be used in
> interfaces, which means no operator overloading in interfaces.

Interfaces allow final methods which should help.

> Related bug:
>
> http://d.puremagic.com/issues/show_bug.cgi?id=4174

That should be what the doctor prescribed. I updated the report and assigned it to Walter.


Andrei
December 29, 2010
On Wed, 29 Dec 2010 15:38:27 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 12/29/10 2:10 PM, Steven Schveighoffer wrote:
>> On Wed, 29 Dec 2010 14:42:53 -0500, Andrei Alexandrescu
>> <SeeWebsiteForEmail@erdani.org> wrote:
>>
>>> On 12/27/10 6:55 PM, Andrei Alexandrescu wrote:
>>>> On 12/27/10 12:35 PM, bearophile wrote:
>>>>> Through Reddit I have found a link to some information about the Clay
>>>>> language, it wants to be (or it will be) a C++-class language, but
>>>>> it's not tied to C syntax. It shares several semantic similarities
>>>>> with D too. It looks like a cute language:
>>>>> https://github.com/jckarter/clay/wiki/
>>>> [snip]
>>>>
>>>> FWIW I just posted a response to a question asking for a comparison
>>>> between Clay and D2.
>>>>
>>>> http://www.reddit.com/r/programming/comments/es2jx/clay_programming_language_wiki/
>>>>
>>>
>>> That thread is shaping up more and more interesting because it's
>>> turning into a discussion of generic programming at large.
>>
>> I wanted to address your post in the reddit discussion regarding the
>> issue of operator overloads not being virtual:
>>
>> "This non-issue has been discussed in the D newsgroup. You can implement
>> virtuals on top of non-virtuals efficiently, but not vice versa."
>>
>> I've found some very real problems with that, when implementing operator
>> overloads in dcollections. It's forced me to use the (yet to be
>> deprecated) opXXX forms. Specifically, you cannot use covariance with
>> templated functions without repeating the entire implementation in the
>> derived class.
>
> Glad you're bringing that up. Could you please post an example that summarizes the issue?

With D1:

interface List
{
   List opCat(List other);
}

class LinkList : List
{
   LinkList opCat(List other) {...}
}

With D2:

interface List
{
   List doCat(List other); // implement this in derived class
   List opBinary(string op)(List other) if (op == "~")
   { return doCat(other); }
}

class LinkList : List
{
   LinkList doCat(List other) {...}
}

// usage;

LinkList ll = new LinkList(1, 2, 3);
ll = ll ~ ll; // works with D1, fails on D2, "can't assign List to LinkList"

Solution is to restate opBinary in all dervied classes with *exact same code* but different return type.  I find this solution unacceptable.

>> Also, let's not forget, templates can't be used in
>> interfaces, which means no operator overloading in interfaces.
>
> Interfaces allow final methods which should help.

operator overloads *must* be templates, and templates aren't allowed, so final methods don't help here.  Actually, final methods can't forward covariance either, so we have issues there.  I think we need a general solution to the covariance problem.  I also have filed a separate bug on covariance not being forwarded by alias.

>
>> Related bug:
>>
>> http://d.puremagic.com/issues/show_bug.cgi?id=4174
>
> That should be what the doctor prescribed. I updated the report and assigned it to Walter.

I saw, thanks.

-Steve
December 29, 2010
On 12/29/10 2:58 PM, Steven Schveighoffer wrote:
> On Wed, 29 Dec 2010 15:38:27 -0500, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> On 12/29/10 2:10 PM, Steven Schveighoffer wrote:
>>> On Wed, 29 Dec 2010 14:42:53 -0500, Andrei Alexandrescu
>>> <SeeWebsiteForEmail@erdani.org> wrote:
>>>
>>>> On 12/27/10 6:55 PM, Andrei Alexandrescu wrote:
>>>>> On 12/27/10 12:35 PM, bearophile wrote:
>>>>>> Through Reddit I have found a link to some information about the Clay
>>>>>> language, it wants to be (or it will be) a C++-class language, but
>>>>>> it's not tied to C syntax. It shares several semantic similarities
>>>>>> with D too. It looks like a cute language:
>>>>>> https://github.com/jckarter/clay/wiki/
>>>>> [snip]
>>>>>
>>>>> FWIW I just posted a response to a question asking for a comparison
>>>>> between Clay and D2.
>>>>>
>>>>> http://www.reddit.com/r/programming/comments/es2jx/clay_programming_language_wiki/
>>>>>
>>>>>
>>>>
>>>> That thread is shaping up more and more interesting because it's
>>>> turning into a discussion of generic programming at large.
>>>
>>> I wanted to address your post in the reddit discussion regarding the
>>> issue of operator overloads not being virtual:
>>>
>>> "This non-issue has been discussed in the D newsgroup. You can implement
>>> virtuals on top of non-virtuals efficiently, but not vice versa."
>>>
>>> I've found some very real problems with that, when implementing operator
>>> overloads in dcollections. It's forced me to use the (yet to be
>>> deprecated) opXXX forms. Specifically, you cannot use covariance with
>>> templated functions without repeating the entire implementation in the
>>> derived class.
>>
>> Glad you're bringing that up. Could you please post an example that
>> summarizes the issue?
>
> With D1:
>
> interface List
> {
> List opCat(List other);
> }
>
> class LinkList : List
> {
> LinkList opCat(List other) {...}
> }
>
> With D2:
>
> interface List
> {
> List doCat(List other); // implement this in derived class
> List opBinary(string op)(List other) if (op == "~")
> { return doCat(other); }
> }
>
> class LinkList : List
> {
> LinkList doCat(List other) {...}
> }
>
> // usage;
>
> LinkList ll = new LinkList(1, 2, 3);
> ll = ll ~ ll; // works with D1, fails on D2, "can't assign List to
> LinkList"
>
> Solution is to restate opBinary in all dervied classes with *exact same
> code* but different return type. I find this solution unacceptable.

I understand, thanks for taking the time to share. The solution to this matter as I see it is integrated with another topic - usually you want to define groups of operators, which means you'd want to define an entire translation layer from static operators to overridable ones.

Here's the code I suggest along those lines. I used a named function instead of a template to avoid 4174:

template translateOperators()
{
    auto ohPeeCat(List other) { return doCat(other); }
}

interface List
{
    List doCat(List other); // implement this in derived class
}

class LinkList : List
{
    LinkList doCat(List other) { return this; }
    mixin translateOperators!();
}

void main(string[] args)
{
    LinkList ll = new LinkList;
    ll = ll.ohPeeCat(ll);
}

The translateOperators template would generally define a battery of operators depending on e.g. whether appropriate implementations are found in the host class (in this case LinkList).


Andrei

December 29, 2010
Andrej Mitrovic:

> But even if you did change the semantics of import to a static import, you still wouldn't fix the *programmers* themselves.

This can't justify a worse design for the language.
And the syntax (and common idioms) of a language have some influence on the way programmers write code. If you give them a new default, some of them will use the new default instead of idioms from other languages they already know.


> And if you doubt that, just take a look at all the Python code that's out there. A ton of programmers still use the star syntax to import every symbol into the current scope,

If I go in the Python Package Index PyPI, I don't see many from foo import *. They are common only when you use code in the shell, or when you write 20 lines long scripts that use good modules. But in those good modules you will not find the import * often.
I guess compared to C programmers the Python community is more willing to follow a common good coding style :-)

Bye,
bearophile
December 30, 2010
On Wed, 29 Dec 2010 16:14:11 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 12/29/10 2:58 PM, Steven Schveighoffer wrote:
>> On Wed, 29 Dec 2010 15:38:27 -0500, Andrei Alexandrescu
>> <SeeWebsiteForEmail@erdani.org> wrote:
>>
>>> On 12/29/10 2:10 PM, Steven Schveighoffer wrote:
>>>> On Wed, 29 Dec 2010 14:42:53 -0500, Andrei Alexandrescu
>>>> <SeeWebsiteForEmail@erdani.org> wrote:
>>>>
>>>>> On 12/27/10 6:55 PM, Andrei Alexandrescu wrote:
>>>>>> On 12/27/10 12:35 PM, bearophile wrote:
>>>>>>> Through Reddit I have found a link to some information about the Clay
>>>>>>> language, it wants to be (or it will be) a C++-class language, but
>>>>>>> it's not tied to C syntax. It shares several semantic similarities
>>>>>>> with D too. It looks like a cute language:
>>>>>>> https://github.com/jckarter/clay/wiki/
>>>>>> [snip]
>>>>>>
>>>>>> FWIW I just posted a response to a question asking for a comparison
>>>>>> between Clay and D2.
>>>>>>
>>>>>> http://www.reddit.com/r/programming/comments/es2jx/clay_programming_language_wiki/
>>>>>>
>>>>>>
>>>>>
>>>>> That thread is shaping up more and more interesting because it's
>>>>> turning into a discussion of generic programming at large.
>>>>
>>>> I wanted to address your post in the reddit discussion regarding the
>>>> issue of operator overloads not being virtual:
>>>>
>>>> "This non-issue has been discussed in the D newsgroup. You can implement
>>>> virtuals on top of non-virtuals efficiently, but not vice versa."
>>>>
>>>> I've found some very real problems with that, when implementing operator
>>>> overloads in dcollections. It's forced me to use the (yet to be
>>>> deprecated) opXXX forms. Specifically, you cannot use covariance with
>>>> templated functions without repeating the entire implementation in the
>>>> derived class.
>>>
>>> Glad you're bringing that up. Could you please post an example that
>>> summarizes the issue?
>>
>> With D1:
>>
>> interface List
>> {
>> List opCat(List other);
>> }
>>
>> class LinkList : List
>> {
>> LinkList opCat(List other) {...}
>> }
>>
>> With D2:
>>
>> interface List
>> {
>> List doCat(List other); // implement this in derived class
>> List opBinary(string op)(List other) if (op == "~")
>> { return doCat(other); }
>> }
>>
>> class LinkList : List
>> {
>> LinkList doCat(List other) {...}
>> }
>>
>> // usage;
>>
>> LinkList ll = new LinkList(1, 2, 3);
>> ll = ll ~ ll; // works with D1, fails on D2, "can't assign List to
>> LinkList"
>>
>> Solution is to restate opBinary in all dervied classes with *exact same
>> code* but different return type. I find this solution unacceptable.
>
> I understand, thanks for taking the time to share. The solution to this matter as I see it is integrated with another topic - usually you want to define groups of operators, which means you'd want to define an entire translation layer from static operators to overridable ones.
>
> Here's the code I suggest along those lines. I used a named function instead of a template to avoid 4174:
>
> template translateOperators()
> {
>      auto ohPeeCat(List other) { return doCat(other); }
> }
>
> interface List
> {
>      List doCat(List other); // implement this in derived class
> }
>
> class LinkList : List
> {
>      LinkList doCat(List other) { return this; }
>      mixin translateOperators!();
> }
>
> void main(string[] args)
> {
>      LinkList ll = new LinkList;
>      ll = ll.ohPeeCat(ll);
> }
>
> The translateOperators template would generally define a battery of operators depending on e.g. whether appropriate implementations are found in the host class (in this case LinkList).

I'm assuming you meant this (once the bug is fixed):

template translateOperators()
{
   auto opBinary(string op)(List other) {return doCat(other);} if (op == "~")
}

and adding this mixin to the interface?

I find this solution extremely convoluted, not to mention bloated, and how do the docs work?  It's like we're going back to C macros!  This operator overloading scheme is way more trouble than the original.

The thing I find ironic is that with the original operator overloading scheme, the issue was that for types that define multiple operator overloads in a similar fashion, forcing you to repeat boilerplate code.  The solution to it was a mixin similar to what you are suggesting.  Except now, even mundane and common operator overloads require verbose template definitions (possibly with mixins), and it's the uncommon case that benefits.  So really, we haven't made any progress (mixins are still required, except now they will be more common).  I think this is one area where D has gotten decidedly worse.  I mean, just look at the difference above between defining the opcat operator in D1 and your mixin solution!

As a compromise, can we work on a way to forward covariance, or to have the compiler reevaluate the template in more derived types?

-Steve
December 30, 2010
On 2010-12-30 10:00:05 -0500, "Steven Schveighoffer" <schveiguy@yahoo.com> said:

> The thing I find ironic is that with the original operator overloading  scheme, the issue was that for types that define multiple operator  overloads in a similar fashion, forcing you to repeat boilerplate code.   The solution to it was a mixin similar to what you are suggesting.  Except  now, even mundane and common operator overloads require verbose template  definitions (possibly with mixins), and it's the uncommon case that  benefits.  So really, we haven't made any progress (mixins are still  required, except now they will be more common).  I think this is one area  where D has gotten decidedly worse.  I mean, just look at the difference  above between defining the opcat operator in D1 and your mixin solution!

I'm with you, I preferred the old design.


> As a compromise, can we work on a way to forward covariance, or to have  the compiler reevaluate the template in more derived types?

I stubbled upon this yesterday:

	Template This Parameters

	TemplateThisParameters are used in member function templates to pick up the type of the this reference.
	import std.stdio;

	struct S
	{
		const void foo(this T)(int i)
		{
			writeln(typeid(T));
		}
	}

<http://www.digitalmars.com/d/2.0/template.html>

Looks like you could return the type of this this way...

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

December 30, 2010
On Thu, 30 Dec 2010 10:22:22 -0500, Michel Fortin <michel.fortin@michelf.com> wrote:

> On 2010-12-30 10:00:05 -0500, "Steven Schveighoffer" <schveiguy@yahoo.com> said:
>
>> The thing I find ironic is that with the original operator overloading  scheme, the issue was that for types that define multiple operator  overloads in a similar fashion, forcing you to repeat boilerplate code.   The solution to it was a mixin similar to what you are suggesting.  Except  now, even mundane and common operator overloads require verbose template  definitions (possibly with mixins), and it's the uncommon case that  benefits.  So really, we haven't made any progress (mixins are still  required, except now they will be more common).  I think this is one area  where D has gotten decidedly worse.  I mean, just look at the difference  above between defining the opcat operator in D1 and your mixin solution!
>
> I'm with you, I preferred the old design.
>
>
>> As a compromise, can we work on a way to forward covariance, or to have  the compiler reevaluate the template in more derived types?
>
> I stubbled upon this yesterday:
>
> 	Template This Parameters
>
> 	TemplateThisParameters are used in member function templates to pick up the type of the this reference.
> 	import std.stdio;
>
> 	struct S
> 	{
> 		const void foo(this T)(int i)
> 		{
> 			writeln(typeid(T));
> 		}
> 	}
>
> <http://www.digitalmars.com/d/2.0/template.html>
>
> Looks like you could return the type of this this way...
>

Damn!  That's very very close to what I wanted!  Thanks for stumbling on that ;)  I don't even need to repeat it at derived levels (just tried it out).

The one issue I see now is, I have to cast this to T, which involves a runtime cast.  From what I understand, covariance does not require a runtime cast penalty, because the adjustment lookup is done at compile time.

I wonder if the compiler can optimize out the runtime dynamic cast in this case, Walter?

Now, for a working (but not quite as effecient as D1) solution, all I need is the bug fix for allowing templates in interfaces.

-Steve