Jump to page: 1 2 3
Thread overview
How about a special null template parameter?
Aug 19, 2016
Engine Machine
Aug 19, 2016
Jack Applegame
Aug 19, 2016
Engine Machine
Aug 19, 2016
Lodovico Giaretta
Aug 19, 2016
Engine Machine
Aug 19, 2016
Lodovico Giaretta
Aug 19, 2016
Engine Machine
Aug 20, 2016
Chris Wright
Aug 19, 2016
Timon Gehr
Aug 19, 2016
Engine Machine
Aug 20, 2016
Timon Gehr
Aug 20, 2016
Engine Machine
Aug 21, 2016
Timon Gehr
Aug 21, 2016
Engine Machine
Aug 22, 2016
Meta
Aug 22, 2016
Engine Machine
Aug 19, 2016
Enamex
Aug 19, 2016
Engine Machine
Aug 19, 2016
Enamex
Aug 20, 2016
poliklosio
Aug 20, 2016
Engine Machine
August 19, 2016
So we can create types relationships easier:

class Type(T) : Type!null
{
   int x;
   static if (T is Dog)
       int y;
}

Type == Type!null (!null implicit, only if defined in the above way. Essentially an alias is created for us automatically)

Type(T) : Type!nullinherits only if T is not null(or a type that inherits from itself,  which would then be valid).

Type!Dog inherits from Type/Type!null.

Type!T inherits from Type/Type!null as long as T != null.

Members in base(null) are not re-included in derived(e.g., int x; isn't include in Type!Dog because it's already there from base).

This simple syntactic sugar allows us to create multiple classes to create simple inheritance hierarchy.

It replaces the current method of having to define a non-templated class and a templated class.

e.g.,

class Type
{
   int x;
}

class Type(T) : Type
{
   static if (T is Dog)
      int y;
}



vs



class Type(T) : Type!null
{
   int x;
   static if (T is Dog)
       int y;
}







August 19, 2016
On Friday, 19 August 2016 at 18:25:06 UTC, Engine Machine wrote:
> It replaces the current method of having to define a non-templated class and a templated class.
>
> e.g.,
>
> class Type
> {
>    int x;
> }
>
> class Type(T) : Type
> {
>    static if (T is Dog)
>       int y;
> }
What are you talking about? This code doesn't compile. Because you can't define a class and a template with the same name.
August 19, 2016
On Friday, 19 August 2016 at 18:25:06 UTC, Engine Machine wrote:
> So we can create types relationships easier:
>
> class Type(T) : Type!null
> {
>    int x;
>    static if (T is Dog)
>        int y;
> }
>
> Type == Type!null (!null implicit, only if defined in the above way. Essentially an alias is created for us automatically)
>
> Type(T) : Type!nullinherits only if T is not null(or a type that inherits from itself,  which would then be valid).
>
> Type!Dog inherits from Type/Type!null.
>
> Type!T inherits from Type/Type!null as long as T != null.
>
> Members in base(null) are not re-included in derived(e.g., int x; isn't include in Type!Dog because it's already there from base).
>
> This simple syntactic sugar allows us to create multiple classes to create simple inheritance hierarchy.
>
> It replaces the current method of having to define a non-templated class and a templated class.
>
> e.g.,
>
> class Type
> {
>    int x;
> }
>
> class Type(T) : Type
> {
>    static if (T is Dog)
>       int y;
> }
>
>
>
> vs
>
>
>
> class Type(T) : Type!null
> {
>    int x;
>    static if (T is Dog)
>        int y;
> }

1) `null` has a very precise meaning: it is the only valid value of an unnamed type only known as `typeof(null)`, which implicitly converts to any class/pointer/dynamic array/associative array type. Thus this thing should have a different name.

2) What about this case:
```
class Type(T): Type
{
    static if (T is Dog)
        int y;
    else
        float z;
}
```
What should be inside the base?

3) I guess that you may find this useful to write functions that accept any type this way:
```
void myFunction(Type val)
{
    // only use fields in common between all Type instantiations
}
```
But you can already do that this way, which is way more flexible:
```
void myFunction(T)(Type!T val)
{
    // use fields in common between all instantiation,
    // but also fields specific to a certain instantiation,
    // using static if
}
```

4) I think that the value of this addition is little wrt. the amount of work the compiler should do to implement it (which at first sight would be a lot). But this is of course just my opinion.
August 19, 2016
On 19.08.2016 20:25, Engine Machine wrote:
> So we can create types relationships easier:
>
> class Type(T) : Type!null
> {
>    int x;
>    static if (T is Dog)
>        int y;


alias Seq(T...)=T;

template TypeParent(T...) if(T.length==1){
    static if(is(typeof(T[0])==typeof(null))) alias TypeParent = Seq!();
    else alias TypeParent = Seq!(Type!null);
}

class Type(T...): TypeParent!T if(T.length==1){
   int x;
   static if (T is Dog)
       int y;
}

August 19, 2016
On Friday, 19 August 2016 at 19:13:10 UTC, Jack Applegame wrote:
> On Friday, 19 August 2016 at 18:25:06 UTC, Engine Machine wrote:
>> It replaces the current method of having to define a non-templated class and a templated class.
>>
>> e.g.,
>>
>> class Type
>> {
>>    int x;
>> }
>>
>> class Type(T) : Type
>> {
>>    static if (T is Dog)
>>       int y;
>> }
> What are you talking about? This code doesn't compile. Because you can't define a class and a template with the same name.

It doesn't matter. That is just a defect of D/language.

If it confuses you, call it Type_Special_X, or, if that confuses you, call it something else. Don't get caught up in the words old padawan.


August 19, 2016
On Friday, 19 August 2016 at 19:19:35 UTC, Lodovico Giaretta wrote:
> On Friday, 19 August 2016 at 18:25:06 UTC, Engine Machine wrote:
>> So we can create types relationships easier:
>>
>> class Type(T) : Type!null
>> {
>>    int x;
>>    static if (T is Dog)
>>        int y;
>> }
>>
>> Type == Type!null (!null implicit, only if defined in the above way. Essentially an alias is created for us automatically)
>>
>> Type(T) : Type!nullinherits only if T is not null(or a type that inherits from itself,  which would then be valid).
>>
>> Type!Dog inherits from Type/Type!null.
>>
>> Type!T inherits from Type/Type!null as long as T != null.
>>
>> Members in base(null) are not re-included in derived(e.g., int x; isn't include in Type!Dog because it's already there from base).
>>
>> This simple syntactic sugar allows us to create multiple classes to create simple inheritance hierarchy.
>>
>> It replaces the current method of having to define a non-templated class and a templated class.
>>
>> e.g.,
>>
>> class Type
>> {
>>    int x;
>> }
>>
>> class Type(T) : Type
>> {
>>    static if (T is Dog)
>>       int y;
>> }
>>
>>
>>
>> vs
>>
>>
>>
>> class Type(T) : Type!null
>> {
>>    int x;
>>    static if (T is Dog)
>>        int y;
>> }
>
> 1) `null` has a very precise meaning: it is the only valid value of an unnamed type only known as `typeof(null)`, which implicitly converts to any class/pointer/dynamic array/associative array type. Thus this thing should have a different name.

null as many interpretations. It is ok to expand the meaning. It is done all the time. If it confuses you are creates a semantic difficulty, I don't mind what it is called. It could be called Boomfurkasufasdf.

In this case, defining it to be null fits in semantically though. If it creates some compiler issue then, again, anything else could be used. I'd prefer Null or NULL or Aleph or something short and meaningless.



> 2) What about this case:
> ```
> class Type(T): Type
> {
>     static if (T is Dog)
>         int y;
>     else
>         float z;
> }
> ```
> What should be inside the base?

z.


> 3) I guess that you may find this useful to write functions that accept any type this way:
> ```
> void myFunction(Type val)
> {
>     // only use fields in common between all Type instantiations
> }
> ```
> But you can already do that this way, which is way more flexible:
> ```
> void myFunction(T)(Type!T val)
> {
>     // use fields in common between all instantiation,
>     // but also fields specific to a certain instantiation,
>     // using static if
> }
> ```

Well, that is not really what I'm after. I am after simplifying class design.

> 4) I think that the value of this addition is little wrt. the amount of work the compiler should do to implement it (which at first sight would be a lot). But this is of course just my opinion.

It is just syntactic sugar and requires no complex compiler modifications. The benefit is reduced visual complexity and that is always a bonus. That is the point we don't write in 0's and 1's... everything else is just syntactic sugar. In this case, it is a very simple rewrite rule. A few lines of code would be all that is required.



August 19, 2016
On Friday, 19 August 2016 at 21:07:42 UTC, Timon Gehr wrote:
> On 19.08.2016 20:25, Engine Machine wrote:
>> So we can create types relationships easier:
>>
>> class Type(T) : Type!null
>> {
>>    int x;
>>    static if (T is Dog)
>>        int y;
>
>
> alias Seq(T...)=T;
>
> template TypeParent(T...) if(T.length==1){
>     static if(is(typeof(T[0])==typeof(null))) alias TypeParent = Seq!();
>     else alias TypeParent = Seq!(Type!null);
> }
>
> class Type(T...): TypeParent!T if(T.length==1){
>    int x;
>    static if (T is Dog)
>        int y;
> }

This is a bit verbose and not quite right (T is Dog should be something like T[0], or whatever).

It does essentially work. My only complaint is that it would be nice to be able to export an alias to Type!() = Type; in the namespace of the type being created. Doubt that D can do that!? If it can, then it should be an adequate solution.

That is

It would be nice to have something like

alias Type = Type!();
class Type(T...): TypeParent!T if(T.length==1){
    int x;
    static if (T is Dog)
        int y;
}

Again, I don't think D will allow this.


alias Seq(T...)=T;

template TypeParent(T...) {
    static if(is(typeof(T[0])==typeof(null))) alias TypeParent = Seq!();
    else alias TypeParent = Seq!(Type!null);
}

class Type(T...) : TypeParent!T
{
   int x;
   static if(T.length == 1)
   {
	static if (T[0] is Dog)
		int y;
   }
}

(note I removed the length checks, so we can create the base type and such)

I guess a such a method is nice to create compound types though:

Type!(Animal, Dog, Chihuahua)

and have a inheritance chain.

e.g.,


class Type(T...) : TypeParent!T
{
   int x;
   static if(T.length >= 1)
   {
	static if (T[0] is "Animal")
	{
		int z;
		static if (T[1] is "Dog")
			int y;
	}
   }
}


void main()
{
	Type!("Animal", "Dog") t;
}

I don't know if all this obeys inheritance though but it looks like it should.

Thanks!
August 19, 2016
On Friday, 19 August 2016 at 18:25:06 UTC, Engine Machine wrote:
> So we can create types relationships easier:
>
> class Type(T) : Type!null
> {
>    int x;
>    static if (T is Dog)
>        int y;
> }
>
> Type == Type!null (!null implicit, only if defined in the above way. Essentially an alias is created for us automatically)
>
> Type(T) : Type!nullinherits only if T is not null(or a type that inherits from itself,  which would then be valid).
>
> Type!Dog inherits from Type/Type!null.
>
> Type!T inherits from Type/Type!null as long as T != null.
>
> Members in base(null) are not re-included in derived(e.g., int x; isn't include in Type!Dog because it's already there from base).

Something like this:

class Type(T: typeof(null)) { //< L1 (specialization)
    int x;
}

class Dog {}

class Type(T) : Type!(typeof(null)) { //< L2 (`typeof(null)`)
    static if(is(T: Dog)) //< L3 (`is(MyType: IntendedType)` or `is(MyType == ExactType)`)
        int y;
}

What you're looking for is "specialization", on line "L1". Also some corrections on lines "L2" and "L3"
August 19, 2016
On Friday, 19 August 2016 at 21:51:38 UTC, Engine Machine wrote:
> On Friday, 19 August 2016 at 19:19:35 UTC, Lodovico Giaretta wrote:
>> 1) `null` has a very precise meaning: it is the only valid value of an unnamed type only known as `typeof(null)`, which implicitly converts to any class/pointer/dynamic array/associative array type. Thus this thing should have a different name.
>
> null as many interpretations. It is ok to expand the meaning. It is done all the time. If it confuses you are creates a semantic difficulty, I don't mind what it is called. It could be called Boomfurkasufasdf.
>
> In this case, defining it to be null fits in semantically though. If it creates some compiler issue then, again, anything else could be used. I'd prefer Null or NULL or Aleph or something short and meaningless.

The problem is that null is a valid value to instantiate an alias template parameter with. So using it to do something completely different may create ambiguity (does that null means "parent template" or is it a valid instantiation? Who knows). But as you said, this is just a matter of finding a name.


>> 2) What about this case:
>> ```
>> class Type(T): Type
>> {
>>     static if (T is Dog)
>>         int y;
>>     else
>>         float z;
>> }
>> ```
>> What should be inside the base?
>
> z.

This is wrong. If Type has to be the base class of every Type!T, then it cannot contain z, as there is one Type!T (namely Type!Dog) which does not contain z. So in this case the base class Type should be empty. As you see it is not that simple.

> I am after simplifying class design.

Fair enough. Though I'm not sure this is the right way to go.

>> 4) I think that the value of this addition is little wrt. the amount of work the compiler should do to implement it (which at first sight would be a lot). But this is of course just my opinion.
>
> It is just syntactic sugar and requires no complex compiler modifications. The benefit is reduced visual complexity and that is always a bonus. That is the point we don't write in 0's and 1's... everything else is just syntactic sugar. In this case, it is a very simple rewrite rule. A few lines of code would be all that is required.

I'm not an expert, but I think this requires *a lot* of compiler work: it has to analyze every symbol in the class to find out whether it must be part of the "uninstantiated" base or not. And this kind of analysis may not be easy (it may be masked by the use of traits, template mixins, string mixins and so on). Even humans can easily get it wrong (see my previous example).

Also, I thought of other problems:
- Interaction with non-class templates: how should they behave? Or are we just introducing a special case for class templates? (Special cases are very bad, we should limit them).
- Interaction with base classes and interfaces: how is this "uninstantiated base class" inserted into the graph of classes and interfaces? Are interfaces considered implemented by this base class? Is this base class inserted between the templated class and the "original" base class?
August 19, 2016
On Friday, 19 August 2016 at 22:20:09 UTC, Enamex wrote:
> On Friday, 19 August 2016 at 18:25:06 UTC, Engine Machine wrote:
>> [...]
>
> Something like this:
>
> class Type(T: typeof(null)) { //< L1 (specialization)
>     int x;
> }
>
> class Dog {}
>
> class Type(T) : Type!(typeof(null)) { //< L2 (`typeof(null)`)
>     static if(is(T: Dog)) //< L3 (`is(MyType: IntendedType)` or `is(MyType == ExactType)`)
>         int y;
> }
>
> What you're looking for is "specialization", on line "L1". Also some corrections on lines "L2" and "L3"

How is this any different, besides adding meaningless complexity, to inheritence as it already is?
« First   ‹ Prev
1 2 3