Thread overview
std.path.buildPath() and string enumeration
May 30, 2012
nrgyzer
May 30, 2012
bearophile
May 30, 2012
bearophile
May 30, 2012
nrgyzer
May 30, 2012
Artur Skawina
May 30, 2012
Hi,

I've the following enumeration:

enum path : string {

  log1 = "/var/log1",
  log2 = "/var/log2"

}

Now... when I try to do the following:

string subDirectory = "example";

string newPath = buildPath(path.log1, subDirectory);

I get the following errors:

Error: template std.path.buildPath does not match any function template
declaration
Error: template std.path.buildPath(C) if (isSomeChar!(C)) cannot deduce
template function from argument types !()(path,string)
Error: template std.path.buildPath does not match any function template
declaration
Error: template std.path.buildPath(C) if (isSomeChar!(C)) cannot deduce
template function from argument types !()(path,string)

Is this a bug in std.path.buildPath() or is there anything I'm doing wrong?
May 30, 2012
nrgyzer:

> Is this a bug in std.path.buildPath() or is there anything I'm doing wrong?

The signature of buildPath is:

immutable(C)[] buildPath(C)(const(C[])[] paths...);

But your inputs aren't of the same type. Named enum create their own type. You give buildPath a type string and a type path, that is not a string.

There are various solutions, this compiles, but it's not very safe:

buildPath(cast(string)path.log1, subDirectory);

Another solution is to not use a named enum:

enum : string {
    path_log1 = "/var/log1",
    path_log2 = "/var/log2"
}

buildPath(path_log1, subDirectory)

In bugzilla I have asked for an enum property that returns the raw value&type of an enum.

Bye,
bearophile
May 30, 2012
A better solution is to use:

struct Path {
    enum : string {
        log1 = "/var/log1",
        log2 = "/var/log2"
    }
}


Or even just:

struct Path {
    enum string log1 = "/var/log1",
                log2 = "/var/log2";
}

(In D structs, classes and enums start with an upper case).

Bye,
bearophile
May 30, 2012
== Auszug aus bearophile (bearophileHUGS@lycos.com)'s Artikel
> nrgyzer:
> > Is this a bug in std.path.buildPath() or is there anything I'm
> > doing wrong?
> The signature of buildPath is:
> immutable(C)[] buildPath(C)(const(C[])[] paths...);
> But your inputs aren't of the same type. Named enum create their
> own type. You give buildPath a type string and a type path, that
> is not a string.
> There are various solutions, this compiles, but it's not very
> safe:
> buildPath(cast(string)path.log1, subDirectory);
> Another solution is to not use a named enum:
> enum : string {
>      path_log1 = "/var/log1",
>      path_log2 = "/var/log2"
> }
> buildPath(path_log1, subDirectory)
> In bugzilla I have asked for an enum property that returns the
> raw value&type of an enum.
> Bye,
> bearophile

Alright, thanks... but I want to do the following:

foreach(c; __traits(allMembers, path))
 if (!exists(mixin("path." ~ c))) mkdirRecurse(mixin("path." ~ c));

When I use a named enum, I can't use the source above... so I've to cast in the buildPath()-method to my path enumeration or is there any other chance to realize the foreach-loop?
May 30, 2012
On 05/30/12 20:34, nrgyzer wrote:
> Hi,
> 
> I've the following enumeration:
> 
> enum path : string {
> 
>   log1 = "/var/log1",
>   log2 = "/var/log2"
> 
> }
> 
> Now... when I try to do the following:
> 
> string subDirectory = "example";
> 
> string newPath = buildPath(path.log1, subDirectory);
> 
> I get the following errors:
> 
> Error: template std.path.buildPath does not match any function template
> declaration
> Error: template std.path.buildPath(C) if (isSomeChar!(C)) cannot deduce
> template function from argument types !()(path,string)
> Error: template std.path.buildPath does not match any function template
> declaration
> Error: template std.path.buildPath(C) if (isSomeChar!(C)) cannot deduce
> template function from argument types !()(path,string)
> 
> Is this a bug in std.path.buildPath() or is there anything I'm doing wrong?
> 

A bug, as an enum member is supposed to implicitly convert to its base type. [1]

You might be able to work-around it like this

   template _path() {
      enum : string {
        log1 = "/var/log1",
        log2 = "/var/log2"
      }
   }
   alias _path!() path;

artur

[1] Actually, D's "typesafe variadic functions" don't play well with certain other features too, eg

   void f(A...)(A a) {}
   void f()(string[] a...) {}
   f("a", "b"); // expecting the second overload to be called is reasonable,
                // but this isn't what's going to happen.