www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Factory pattern in D

reply "Chris" <wendlec tcd.ie> writes:
What would be the D equivalent of the factory pattern? This 
obviously doesn't work:

struct A {
   int x = 42;
}

struct B {
   int x = 7;
}

auto factory(string type) {
   if (type == "A")
     return A();
   else if (type == "B")
     return B();
   else
     return A();  // default
}

void main()
{
   auto a = factory("A");
}

Error: mismatched function return type inference of B and A

(dmd 2.067.1)
May 01 2015
next sibling parent reply "Namespace" <rswhite4 gmail.com> writes:
How about this:

----
struct A {
   int x = 42;
}

struct B {
   int x = 7;
}

T factory(T)() {
   return T();
}

void main()
{
   auto a = factory!(A);
}
----
May 01 2015
next sibling parent "Namespace" <rswhite4 gmail.com> writes:
On Friday, 1 May 2015 at 10:04:46 UTC, Namespace wrote:
 How about this:

 ----
 struct A {
   int x = 42;
 }

 struct B {
   int x = 7;
 }

 T factory(T)() {
   return T();
 }

 void main()
 {
   auto a = factory!(A);
 }
 ----
Of course, you can restrict the type to A or B, or both: ---- T factory(T)() if (is(T == A) || is(T == B)) { return T(); } ----
May 01 2015
prev sibling parent reply "Chris" <wendlec tcd.ie> writes:
On Friday, 1 May 2015 at 10:04:46 UTC, Namespace wrote:
 How about this:

 ----
 struct A {
   int x = 42;
 }

 struct B {
   int x = 7;
 }

 T factory(T)() {
   return T();
 }

 void main()
 {
   auto a = factory!(A);
 }
 ----
That's what I was looking for, I just couldn't get it right. Thanks. Rikki: I wanted to avoid classes and interfaces.
May 01 2015
parent reply "biozic" <dransic gmail.com> writes:
On Friday, 1 May 2015 at 10:12:36 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:04:46 UTC, Namespace wrote:
 How about this:

 ----
 struct A {
  int x = 42;
 }

 struct B {
  int x = 7;
 }

 T factory(T)() {
  return T();
 }

 void main()
 {
  auto a = factory!(A);
 }
 ----
That's what I was looking for, I just couldn't get it right. Thanks. Rikki: I wanted to avoid classes and interfaces.
This might be a bit more useful: --- struct A { int x = 42; } struct B { int x = 7; } auto factory(string type = "")() { static if (type == "A") return A(); else static if (type == "B") return B(); else return A(); // default } void main() { auto a = factory!"A"; auto b = factory!"B"; auto x = factory; } ---
May 01 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Friday, 1 May 2015 at 10:27:16 UTC, biozic wrote:
 On Friday, 1 May 2015 at 10:12:36 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:04:46 UTC, Namespace wrote:
 How about this:

 ----
 struct A {
 int x = 42;
 }

 struct B {
 int x = 7;
 }

 T factory(T)() {
 return T();
 }

 void main()
 {
 auto a = factory!(A);
 }
 ----
That's what I was looking for, I just couldn't get it right. Thanks. Rikki: I wanted to avoid classes and interfaces.
This might be a bit more useful: --- struct A { int x = 42; } struct B { int x = 7; } auto factory(string type = "")() { static if (type == "A") return A(); else static if (type == "B") return B(); else return A(); // default } void main() { auto a = factory!"A"; auto b = factory!"B"; auto x = factory; } ---
Duh, I tried `static if` yesterday and I still got "Error: mismatched function return type inference of B and A". Now it works! Sure, I must have overlooked something. Sometimes it's better to go home and call it a day than to try to get something to work.
May 01 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Friday, 1 May 2015 at 10:46:20 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:27:16 UTC, biozic wrote:
 On Friday, 1 May 2015 at 10:12:36 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:04:46 UTC, Namespace wrote:
 How about this:

 ----
 struct A {
 int x = 42;
 }

 struct B {
 int x = 7;
 }

 T factory(T)() {
 return T();
 }

 void main()
 {
 auto a = factory!(A);
 }
 ----
That's what I was looking for, I just couldn't get it right. Thanks. Rikki: I wanted to avoid classes and interfaces.
This might be a bit more useful: --- struct A { int x = 42; } struct B { int x = 7; } auto factory(string type = "")() { static if (type == "A") return A(); else static if (type == "B") return B(); else return A(); // default } void main() { auto a = factory!"A"; auto b = factory!"B"; auto x = factory; } ---
Duh, I tried `static if` yesterday and I still got "Error: mismatched function return type inference of B and A". Now it works! Sure, I must have overlooked something. Sometimes it's better to go home and call it a day than to try to get something to work.
And thanks, by the way!
May 01 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Friday, 1 May 2015 at 10:47:22 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:46:20 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:27:16 UTC, biozic wrote:
 On Friday, 1 May 2015 at 10:12:36 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:04:46 UTC, Namespace wrote:
 How about this:

 ----
 struct A {
 int x = 42;
 }

 struct B {
 int x = 7;
 }

 T factory(T)() {
 return T();
 }

 void main()
 {
 auto a = factory!(A);
 }
 ----
That's what I was looking for, I just couldn't get it right. Thanks. Rikki: I wanted to avoid classes and interfaces.
This might be a bit more useful: --- struct A { int x = 42; } struct B { int x = 7; } auto factory(string type = "")() { static if (type == "A") return A(); else static if (type == "B") return B(); else return A(); // default } void main() { auto a = factory!"A"; auto b = factory!"B"; auto x = factory; } ---
Duh, I tried `static if` yesterday and I still got "Error: mismatched function return type inference of B and A". Now it works! Sure, I must have overlooked something. Sometimes it's better to go home and call it a day than to try to get something to work.
And thanks, by the way!
Thinking about it, T factory(T)() { return T(); } is better suited for a factory (with static type checks). This aside, how would I get something to load dynamically? It's either "mismatched function return type" or (with type check) "variable X cannot be read at compile time": void main(string[] args) { auto type = args[1]; auto myType = factory!type(); } So it's back to classes/interfaces again? Hmmmm.
May 01 2015
next sibling parent reply "biozic" <dransic gmail.com> writes:
On Friday, 1 May 2015 at 11:01:29 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:47:22 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:46:20 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:27:16 UTC, biozic wrote:
 On Friday, 1 May 2015 at 10:12:36 UTC, Chris wrote:
 On Friday, 1 May 2015 at 10:04:46 UTC, Namespace wrote:
 How about this:

 ----
 struct A {
 int x = 42;
 }

 struct B {
 int x = 7;
 }

 T factory(T)() {
 return T();
 }

 void main()
 {
 auto a = factory!(A);
 }
 ----
That's what I was looking for, I just couldn't get it right. Thanks. Rikki: I wanted to avoid classes and interfaces.
This might be a bit more useful: --- struct A { int x = 42; } struct B { int x = 7; } auto factory(string type = "")() { static if (type == "A") return A(); else static if (type == "B") return B(); else return A(); // default } void main() { auto a = factory!"A"; auto b = factory!"B"; auto x = factory; } ---
Duh, I tried `static if` yesterday and I still got "Error: mismatched function return type inference of B and A". Now it works! Sure, I must have overlooked something. Sometimes it's better to go home and call it a day than to try to get something to work.
And thanks, by the way!
Thinking about it, T factory(T)() { return T(); } is better suited for a factory (with static type checks).
But then I don't know what factory!X() provides that X() alone doesn't.
 This aside, how would I get something to load dynamically? It's 
 either "mismatched function return type" or (with type check) 
 "variable X cannot be read at compile time":

 void main(string[] args) {
  auto type = args[1];
  auto myType = factory!type();
 }

 So it's back to classes/interfaces again? Hmmmm.
Indeed. Runtime polymorphism is based on classes and interfaces. The struct and template solutions can only make "compile-time factories".
May 01 2015
parent reply "Chris" <wendlec tcd.ie> writes:
On Friday, 1 May 2015 at 11:11:28 UTC, biozic wrote:
 On Friday, 1 May 2015 at 11:01:29 UTC, Chris wrote:
 Thinking about it,

 T factory(T)() {
  return T();
 }

 is better suited for a factory (with static type checks).
But then I don't know what factory!X() provides that X() alone doesn't.
Just cleaner code with type checks T factory(T)() { static if (is (T == A) || (is (T == B))) return T(); else assert(0, "Type "~T.stringof~" is not supported"); } and then you could have auto getType(string type = "")() { static if (type == "A") return factory!A(); else static if (type == "B") return factroy!B(); else return factory!A(); // default } in order to separate the logic, i.e. the factory produces the type and performs all the type checks, whereas `getType` is the interface for the user.
 This aside, how would I get something to load dynamically? 
 It's either "mismatched function return type" or (with type 
 check) "variable X cannot be read at compile time":

 void main(string[] args) {
 auto type = args[1];
 auto myType = factory!type();
 }

 So it's back to classes/interfaces again? Hmmmm.
Indeed. Runtime polymorphism is based on classes and interfaces. The struct and template solutions can only make "compile-time factories".
Yep. Only that "compile-time factories" kinda defeat the purpose.
May 01 2015
parent "biozic" <dransic gmail.com> writes:
On Friday, 1 May 2015 at 11:20:32 UTC, Chris wrote:
 On Friday, 1 May 2015 at 11:11:28 UTC, biozic wrote:
 On Friday, 1 May 2015 at 11:01:29 UTC, Chris wrote:
 Thinking about it,

 T factory(T)() {
 return T();
 }

 is better suited for a factory (with static type checks).
But then I don't know what factory!X() provides that X() alone doesn't.
Just cleaner code with type checks T factory(T)() { static if (is (T == A) || (is (T == B))) return T(); else assert(0, "Type "~T.stringof~" is not supported"); } and then you could have auto getType(string type = "")() { static if (type == "A") return factory!A(); else static if (type == "B") return factroy!B(); else return factory!A(); // default } in order to separate the logic, i.e. the factory produces the type and performs all the type checks, whereas `getType` is the interface for the user.
A "factory" that produces a *type* could be: -- template checked(T) { static if (is (T == A) || (is (T == B))) alias checked = T; else static assert(0, "Type "~T.stringof~" is not supported"); } --
May 01 2015
prev sibling parent "anonymous" <anonymous example.com> writes:
On Friday, 1 May 2015 at 11:01:29 UTC, Chris wrote:
 This aside, how would I get something to load dynamically? It's 
 either "mismatched function return type" or (with type check) 
 "variable X cannot be read at compile time":

 void main(string[] args) {
  auto type = args[1];
  auto myType = factory!type();
 }

 So it's back to classes/interfaces again? Hmmmm.
Obviously, myType's static type and factory's return type can't depend on a dynamic value like args[1]. You could let factory return a std.variant.Variant, but at that point maybe just go with classes.
May 01 2015
prev sibling parent Rikki Cattermole <alphaglosined gmail.com> writes:
On 1/05/2015 10:01 p.m., Chris wrote:
 What would be the D equivalent of the factory pattern? This obviously
 doesn't work:

 struct A {
    int x = 42;
 }

 struct B {
    int x = 7;
 }

 auto factory(string type) {
    if (type == "A")
      return A();
    else if (type == "B")
      return B();
    else
      return A();  // default
 }

 void main()
 {
    auto a = factory("A");
 }

 Error: mismatched function return type inference of B and A

 (dmd 2.067.1)
Interfaces/classes not structs.
May 01 2015