www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - "instanceOf" trait for conditional implementations

reply "monarch_dodra" <monarchdodra gmail.com> writes:
One of the issues I've been running into more or less frequently 
lately is the inability to extract an instance of a type when 
trying to do conditional implementation specification.

Let me explain myself. Using T.init is a no go, because:
a) T might be " disabled this()", making T.init illegal syntax 
(in theory, currently "buggy")
b) T.init is NOT an LValue, making code such is "is(typeof(T.init 
= 5))" invalid
c) You can try to use "T t = void", but you may also run into 
problems:
c)1) If T is immutable, that's illegal.
c)2) The compiler may complain if you use t, due to access to 
uninitialized.

This makes it a pain in the ass, as shown in this thread:
http://forum.dlang.org/thread/mailman.224.1348358069.5162.digitalmars-d-learn puremagic.com

Or this pull request:
https://github.com/D-Programming-Language/phobos/pull/832

The current implementation for "isAssignable" is
//----
template isAssignable(Lhs, Rhs)
{
     enum bool isAssignable = is(typeof({
         Lhs l = void;
         void f(Rhs r) { l = r; }
         return l;
     }));
}
//----

The code is correct, but when you have to jump through that many 
loops, you have to admit there is probably something wrong.

Imagine you are writting a template "Foo" that only works if it 
is legal to pass an instance of T to a function Bar. Are you 
*really* going to write the same thing as above, inside a single 
conditional if?!

//******************************************
I'd like to propose an "instanceOf(T)" traits template, that 
would return an LValue instance of T. It would be used (strictly) 
for evaluating conditional implementations, or for the 
implementation of traits types.

//----
template instanceOf(T)
{
     static if (is(typeof({T t;})))
         T instanceOf;
     else
         T instanceOf = void;
}
//----

Now, watch this
//----
template isAssignable(T, U)
{
     enum bool isAssignable = is(typeof(instanceOf!T = 
instanceOf!U));
}

struct S
{
      disable this();
}

void main()
{
     static assert( isAssignable!(int, int));
     static assert( isAssignable!(int, immutable(int)));
     static assert(!isAssignable!(immutable(int), int));
     static assert( isAssignable!(S, immutable(S))); //Tricky test 
BTW
}
//----
See? Easy peasy.

And this is just a "simple" test case: assign-ability. There are 
a bunch of other traits templates which would benefit here.

And that's the "tip of the iceberg": There are a TON of 
algorithms that use .init in their implementation restrictions: 
"if (Range.init.front ...)"

instanceOf would be a convenient way to support any type, 
regardless of construct-ability (or lack thereof).

//--------
That's my idea anyways, they've been consistently destroyed 
recently, so I don't mind again if you think it is a bad idea, or 
the approach is wrong.

I *do* think that being able to extract an instance of a type 
without worrying about how to actually acquire one...
Oct 04 2012
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 4 October 2012 at 09:43:08 UTC, monarch_dodra wrote:
 [SNIP]

You know what? Forget I said anything? Using lambdas is an incredibly good workaround for all the problems stated above, making the initial point moot. Lamba if: template isAssignable(T, U) { enum bool isAssignable = is(typeof((ref T t, ref U u) => {t = u;})); } This allow testing on t and u, without ever having to construct/acquire them. Neat-o!!!
Oct 04 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Thursday, 4 October 2012 at 09:43:08 UTC, monarch_dodra wrote:

 The current implementation for "isAssignable" is
 //----
 template isAssignable(Lhs, Rhs)
 {
     enum bool isAssignable = is(typeof({
         Lhs l = void;
         void f(Rhs r) { l = r; }
         return l;
     }));
 }

OT - Is there any reason for disabling UFCS for this? template isAssignable(Lhs, Rhs) { enum bool isAssignable = { Lhs l = void; void f(Rhs r) { l = r; } return l; }.typeof.is; }
Oct 04 2012
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 4 October 2012 at 12:48:51 UTC, so wrote:
 On Thursday, 4 October 2012 at 09:43:08 UTC, monarch_dodra 
 wrote:

 The current implementation for "isAssignable" is
 //----
 template isAssignable(Lhs, Rhs)
 {
    enum bool isAssignable = is(typeof({
        Lhs l = void;
        void f(Rhs r) { l = r; }
        return l;
    }));
 }

OT - Is there any reason for disabling UFCS for this? template isAssignable(Lhs, Rhs) { enum bool isAssignable = { Lhs l = void; void f(Rhs r) { l = r; } return l; }.typeof.is; }

Because typeof is a keyword, and is is a declaration. There are two open ER to allow typeof to be used as a property: While not strictly EFCS, it would be convenient. Regarding is, There are no open requests. But I guess it would be fun to write if( T.is(U) ). But where would it end? Make if UFCS too? T.is(U).if() IMO, I can see typeof being a property, but not is.
Oct 04 2012
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
2012/10/4 monarch_dodra <monarchdodra gmail.com>:
 One of the issues I've been running into more or less frequently lately is
 the inability to extract an instance of a type when trying to do conditional
 implementation specification.

 Let me explain myself. Using T.init is a no go, because:
 a) T might be " disabled this()", making T.init illegal syntax (in theory,
 currently "buggy")

I think T.init should always legal.
 b) T.init is NOT an LValue, making code such is "is(typeof(T.init = 5))"
 invalid

 c) You can try to use "T t = void", but you may also run into problems:
 c)1) If T is immutable, that's illegal.
 c)2) The compiler may complain if you use t, due to access to uninitialized.

IMO, this is just a compiler bug. If a variable has VoidInitializer, it should always become a runtime value. Kenji Hara
Oct 04 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Thursday, 4 October 2012 at 17:44:48 UTC, kenji hara wrote:
 a) T might be " disabled this()", making T.init illegal syntax 
 (in theory,
 currently "buggy")

I think T.init should always legal.

What would be the semantics of T.init for a type with disable this()? It isn't a valid value, for sure... David
Oct 04 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2012-37-04 11:10, monarch_dodra <monarchdodra gmail.com> wrote:

 One of the issues I've been running into more or less frequently lately  
 is the inability to extract an instance of a type when trying to do  
 conditional implementation specification.

 Let me explain myself. Using T.init is a no go, because:
 a) T might be " disabled this()", making T.init illegal syntax (in  
 theory, currently "buggy")
 b) T.init is NOT an LValue, making code such is "is(typeof(T.init = 5))"  
 invalid
 c) You can try to use "T t = void", but you may also run into problems:
 c)1) If T is immutable, that's illegal.
 c)2) The compiler may complain if you use t, due to access to  
 uninitialized.

I like this, and have had the exact same thought. There is one thing I don't like, and that is your instanceOf could be used to create an uninitialized T. In the interest of that (and brevity) let me present my solution: property T instanceOf( T )( ); It works great in static if, and fails at link-time. The error message is however far from perfect: Error 42: Symbol Undefined _D3foo24__T10instanceOfTS3foo1SZ10instanceOfFNdZS3foo1S But I think that is better than giving developers a tool for instantiating types that are not meant to be instantiated. -- Simen
Oct 04 2012
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 4 October 2012 at 17:57:51 UTC, Simen Kjaeraas wrote:
 [SNIP]

  property T instanceOf( T )( );

 [SNIP]

Awesome! It is much more robust too! I still don't understand how *my* instanceOf!(immutable(S)) works :/ I'd just change it to: property ref T instanceOf( T )( ); So that instanceOf acts as an LValue. Having a link error is great too. A compile error would be best, but unachievable actually, so still pretty good.
Oct 04 2012
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 4 October 2012 at 09:43:08 UTC, monarch_dodra wrote:
 [SNIP]

An ER has been opened. http://d.puremagic.com/issues/show_bug.cgi?id=8762
Oct 05 2012
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Thu, 04 Oct 2012 14:43:00 +0200
schrieb "so" <so so.so>:

 OT - Is there any reason for disabling UFCS for this?
 
 template isAssignable(Lhs, Rhs)
 {
      enum bool isAssignable =
      {
          Lhs l = void;
          void f(Rhs r) { l = r; }
          return l;
      }.typeof.is;
 }

Yoda says: "This proposal a special type of is!" -- Marco
Oct 10 2012