On Wed, 29 Dec 2010 16:14:11 -0500, Andrei Alexandrescu
<[email protected]> wrote:
On 12/29/10 2:58 PM, Steven Schveighoffer wrote:
On Wed, 29 Dec 2010 15:38:27 -0500, Andrei Alexandrescu
<[email protected]> wrote:
On 12/29/10 2:10 PM, Steven Schveighoffer wrote:
On Wed, 29 Dec 2010 14:42:53 -0500, Andrei Alexandrescu
<[email protected]> 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