Re: class template conflict

2018-12-25 Thread Michelle Long via Digitalmars-d-learn

On Tuesday, 25 December 2018 at 18:34:04 UTC, bauss wrote:
On Monday, 24 December 2018 at 00:24:05 UTC, Michelle Long 
wrote:

More simple is : do not use the same identifier ;)


The whole point is to use the same identifier ;/


I think there is a bigger problem at stake here in terms of 
software architecture.




No, the problem is reasoning from the conclusion...


Re: class template conflict

2018-12-25 Thread Neia Neutuladh via Digitalmars-d-learn
On Tue, 25 Dec 2018 18:34:04 +, bauss wrote:
> I think there is a bigger problem at stake here in terms of software
> architecture.
> 
> What's the point needed for them to have the same identifier?

A probably abstract base class with only one child class. Normally you 
have "Foo" and "FooImpl", or "IFoo" and "Foo", but that's ugly.

This was the primary example that Michelle Long gave. I'd expect that a 
fair portion of people people who have used C# encountered this kind of 
situtaion. Like this sort of thing works in C#:

class Foo {}
class Foo : Foo {}
class Foo : Foo {}

You can do this in C# because each of these are *classes*, and some just 
happen to have type parameters. In D, you'd have one class and two 
templates, and you can't overload two symbols of different kinds, so you 
have to write it as:

class Foo() {}
class Foo(T): Foo!() {}
class Foo(T, U): Foo!() {}

In Java, for legacy reasons, this pattern is baked into the language; 
Foo always has another class, Foo, that it implicitly casts to and 
from. Some people take advantage of that.

Most people who do both metaprogramming and OOP in D and have been doing 
that for a nontrivial amount of time probably encountered this exact same 
thing in D. I encountered it the first time before D2 was a thing.

> Clearly the two classes will have two different functions and should be
> named accordingly.

They will have different implementations and may have different 
interfaces. The proposed use case is inheritance, so X!10's public 
interface will be a superset of X's (and likely identical).

To give a slightly less contrived example, let's say you want to have some 
functions available to a scripting language. (I'm doing something like 
this in a side project for a CLI spreadsheet program.) Each function has a 
display name, help text, argument validation, and the function body.

If I had done this in an OOP style (and I might end up reworking it to look 
more like this), I'd have something like:

interface Function
{
  string helpText();
  string name();
  Nullable!Error validateParameters(Val[] parameters);
  Val execute(Val[] parameters);
}

And then I'd have a convenience mechanism to produce a conforming class 
from a function with UDAs:

class FunctionImpl(alias fn) : Function
{
override:
  string helpText() { return getUDAs!(fn, Help)[0].text; }
  string name() { return __traits(identifier, fn); }
  // etc
}

It would be slightly nicer to just have "Function" everywhere instead of 
both Function and FunctionImpl. Not enough to justify the complexity of 
the symbol lookup rules required. Not enough to make `class Foo(T)` mean 
something different from `template Foo(T) class Foo`. But it *would* be 
slightly nicer, and it would make things slightly more straightforward for 
people coming from C#.


Re: class template conflict

2018-12-25 Thread bauss via Digitalmars-d-learn

On Monday, 24 December 2018 at 00:24:05 UTC, Michelle Long wrote:

More simple is : do not use the same identifier ;)


The whole point is to use the same identifier ;/


I think there is a bigger problem at stake here in terms of 
software architecture.


What's the point needed for them to have the same identifier?

Clearly the two classes will have two different functions and 
should be named accordingly.


Ex.

class X { ... }

class X(int N) { ... }

Could be something like:

class X { ... }

class XWithArguments { ... }

There is absolutely no point of them having same identifiers 
unless they did the exact same thing and in that case you'd 
probably just not want this anyway.


A solution to this would be something like:

interface X { }

class XWithoutArguments : X { }

class XWithArguments : X { }


Re: class template conflict

2018-12-25 Thread Neia Neutuladh via Digitalmars-d-learn
On Tue, 25 Dec 2018 16:55:36 +, Neia Neutuladh wrote:

And I forgot part of it.

Let's say we did the work to make this function:

class X {}
template X(int N)
{
  // `: X` somehow refers to the X in the outer scope
  class X : X {}
}

How do you distinguish between the base class and the derived class in 
there? You'd have to use typeof(this) and typeof(super) everywhere.

And externally, how do you refer to class X and template X separately? If 
you have a template with an alias parameter and pass X, how do you pass 
class-X and how do you pass template-X?

This is already unpleasant with functions, and there's a way to 
distinguish them.


Re: class template conflict

2018-12-25 Thread Neia Neutuladh via Digitalmars-d-learn
On Tue, 25 Dec 2018 13:03:13 +, Michelle Long wrote:
> But I am not talking about inside the template being used. The whole
> point of doing this is so that one can refer to the base class using the
> same name as the derived with a template parameter to make a composite
> structure.

The following are entirely equivalent:

class X(int N) : X {}

template X(int N)
{
  class X : X {}
}

You want to be able to do, essentially:

class X {}
template X(int N)
{
  // `: X` somehow refers to the X in the outer scope
  class X : X {}
}

And sure, this specific case obviously doesn't work if the `: X` refers to 
the template or the class inside the template. But the symbol lookup rules 
aren't "try everything and see what sticks". You look up the nearest 
symbol and then you just use that.

It would be like arguing that, in the following example, the compiler 
should know that ints aren't callable and should call the function:

void foo() { writeln("merr critmis"); }
void main()
{
int foo = 10;
foo();
}

Which isn't obviously wrong, but it does make things harder to understand.


Re: class template conflict

2018-12-25 Thread Michelle Long via Digitalmars-d-learn

On Monday, 24 December 2018 at 22:55:55 UTC, Daniel Kozak wrote:
ne 23. 12. 2018 13:10 odesílatel Michelle Long via 
Digitalmars-d-learn < digitalmars-d-learn@puremagic.com> napsal:



class X
{

}

class X(int N) : X
{

}

Is there any real reason we can't do this?


Actually yes.  It would break almost all of my code.


How would it break your code?



In D you can do thing like this:
class X(int N)
{
X something; // it is same as X!N something;
}

So I do not need to write X!N everywhere inside X class template


But I am not talking about inside the template being used. The 
whole point of doing this is so that one can refer to the base 
class using the same name as the derived with a template 
parameter to make a composite structure.


X!N should be totally different than X.

The fact that you can use X inside a class to refer to X!N is a 
hack... and in any case should not effect what I'm talking about 
because it is only used in the inherited part.. which it would be 
circular to use it as it is:


class X(int N) : X
{

}

creates circular inheritance.

so for the inherited part it should never be used and you never 
use it in your code like that... so it won't break anything.


Also, as long as there is no other symbol with that name it won't 
break anything.


Suppose this did work:

class X;

class X(int N) : X // (Here X refers to the base class above
{
  // Using X can still be X!N since we can just alias the 
original X away.

}

class X;
alias XX = X;
class X(int N) : X
{
   X x; // X!N x;
   XX xx; // X = x;
}

So it would not break anything. It really has nothing to do with 
what one does inside a template but how it looks to the outside.





Re: class template conflict

2018-12-24 Thread Daniel Kozak via Digitalmars-d-learn
ne 23. 12. 2018 13:10 odesílatel Michelle Long via Digitalmars-d-learn <
digitalmars-d-learn@puremagic.com> napsal:

> class X
> {
>
> }
>
> class X(int N) : X
> {
>
> }
>
> Is there any real reason we can't do this?

Actually yes.  It would break almost all of my code.

In D you can do thing like this:
class X(int N)
{
X something; // it is same as X!N something;
}

So I do not need to write X!N everywhere inside X class template


Re: class template conflict

2018-12-23 Thread Steven Schveighoffer via Digitalmars-d-learn

On 12/23/18 7:09 AM, Michelle Long wrote:

class X
{

}

class X(int N) : X
{

}

Is there any real reason we can't do this?


I think it has less to do with class names and more to do with symbol 
overloading.


The only place I think templates are allowed to overload names with 
non-templates is functions, which actually was not always the case (you 
used to have to only have templates or non templates as function overloads).




It is very nice to be able to treat X like the base and X!n as a derived 
class.


The problem I see is:

template foo(alias A) { ... }

foo!X

Did you mean class X or template X?

For functions, this is OK, because it's one overload set.

-Steve


Re: class template conflict

2018-12-23 Thread Michelle Long via Digitalmars-d-learn

More simple is : do not use the same identifier ;)


The whole point is to use the same identifier ;/


Re: class template conflict

2018-12-23 Thread Basile B. via Digitalmars-d-learn

On Sunday, 23 December 2018 at 12:09:31 UTC, Michelle Long wrote:

class X
{

}

class X(int N) : X
{

}

Is there any real reason we can't do this?

It is very nice to be able to treat X like the base and X!n as 
a derived class.


Sure we can do

class X(int N) : X!0
{
   static if(N == 0)
   {
   }
}

but this is very ugly, in my code I always have to use X!0 as 
the basis!


I do not think there is any harm to allow this since the 
templated class always has to specify N. It is not like we can 
do


class X(int N = 0) : X
{
   static if(N == 0)
   {
   }
}


Actually we can, so... I don't see the point in not allowing 
the first case, they are logically equivalent. That static if 
is just ugly and it is defining the base class inside the 
derived class which seems unnatural.


You have this option too:

```
template X(N...)
if (N.length == 0 ||
N.length == 1 && is(typeof(N[0]) == int))
{
static if (N.length == 0)
class X {}

else class X : X!() {}
}

auto base = new X!();
auto derived = new X!8;
```

More simple is : do not use the same identifier ;)


class template conflict

2018-12-23 Thread Michelle Long via Digitalmars-d-learn

class X
{

}

class X(int N) : X
{

}

Is there any real reason we can't do this?

It is very nice to be able to treat X like the base and X!n as a 
derived class.


Sure we can do

class X(int N) : X!0
{
   static if(N == 0)
   {
   }
}

but this is very ugly, in my code I always have to use X!0 as the 
basis!


I do not think there is any harm to allow this since the 
templated class always has to specify N. It is not like we can do


class X(int N = 0) : X
{
   static if(N == 0)
   {
   }
}


Actually we can, so... I don't see the point in not allowing the 
first case, they are logically equivalent. That static if is just 
ugly and it is defining the base class inside the derived class 
which seems unnatural.