Thread overview
Compiler complaining about code that can't be reached, builtin types .equals()
Jun 25, 2015
Sean Grimes
Jun 25, 2015
Ali Çehreli
Jun 25, 2015
Sean Grimes
June 25, 2015
I have a method, containsValue() in a class similar to java.util.HashMap.
The class is a template class, instantiated with 2 parameters, K key, V value.

bool containsValue(V value){

    // dlang associative array, .values returns dynamic array of values in the aa
    auto values = this.internal_arr.values;

     /*
      * isBuiltIn() checks against all the builtin types in D
      * returns true if value instantiated as int, double, immutable(char)[] etc...
      * returns false iff value is a user defined object
      */
    if(!isBuiltIn(value)){
        foreach(val; values){
            if(val.equals(value))
	        return true;
        }
    }

    // isBuiltin() false, assume builtin type, use "==" for comparison
    else{
        foreach(val; values){
            if(val == value)
                return true;
       }
    }
    return false;
}

The problem I'm having is using a D builtin type for the value parameter. The compiler tells me "no property 'equals' for type 'string'" in the containsValue() method. Well that's well and good, but I already know that which is why I check if the class has been instantiated with a builtin type or a user defined type.

My question: Is there any way around the compiler complaining about this? The code doesn't allow (as best I can tell) the .equals() method to be called when "value" is a builtin type, so why does the compiler still complain?

As a side note, I couldn't get std.traits.isBuiltinType(T) to work, so the function isBuiltIn() is not just calling std.traits.isBuiltinType(T), it's checking the typeid(value) against D builtin typeids.
June 25, 2015
On 06/25/2015 11:26 AM, Sean Grimes wrote:

>       /*
>        * isBuiltIn() checks against all the builtin types in D
>        * returns true if value instantiated as int, double,
> immutable(char)[] etc...
>        * returns false iff value is a user defined object
>        */
>      if(!isBuiltIn(value)){
>          foreach(val; values){
>              if(val.equals(value))
>              return true;
>          }
>      }

That is a run-time conditional. There is no guarantee for the compiler that isBuiltIn() will return 'true' for every 'value'. For example, it can return 'false' for 42 but 'true' for 43.

To enable or disable code sections you can use 'static if'. However, isBuiltIn must be evaluable at compile time as well. Since isBuiltIn works with values (not types) in your case, you can't pass it to 'static if':

    static if (!isBuiltIn(value)) {  // <-- compilation error

You want isBuiltIn to be a template which works on a type (V in your case).

Here is a short example which treats 'int' and 'double' as built-in only:

import std.typetuple;

bool isBuiltIn(T)()
{
    foreach (T2; TypeTuple!(int, double/*, ... */)) {
        if (is (T2 == T)) {
            return true;
        }
    }

    return false;
}

struct S(V)
{
    void foo(V v)
    {
        static if (!isBuiltIn!V) {
            /* Assumes that non-built-ins support bar(). */
            v.bar();
        }
    }
}

void main()
{
    auto s = S!int();
    s.foo(42);
}

Ali

June 25, 2015
On Thursday, 25 June 2015 at 18:43:31 UTC, Ali Çehreli wrote:
> On 06/25/2015 11:26 AM, Sean Grimes wrote:
>
> Here is a short example which treats 'int' and 'double' as built-in only:
>
> import std.typetuple;
>
> bool isBuiltIn(T)()
> {
>     foreach (T2; TypeTuple!(int, double/*, ... */)) {
>         if (is (T2 == T)) {
>             return true;
>         }
>     }
>
>     return false;
> }
>
> struct S(V)
> {
>     void foo(V v)
>     {
>         static if (!isBuiltIn!V) {
>             /* Assumes that non-built-ins support bar(). */
>             v.bar();
>         }
>     }
> }
>
> void main()
> {
>     auto s = S!int();
>     s.foo(42);
> }
>
> Ali

Ali,

Thanks that works for me.

- Sean