digitalmars.D.learn - Singleton Object, calling member functions using UFCS (an "ugly?"
- james.p.leblanc (87/87) Sep 01 2021 Dear D-ers,
- user1234 (13/25) Sep 01 2021 hello, I'd suggest this:
- james.p.leblanc (29/59) Sep 01 2021 user1234,
- user1234 (39/42) Sep 01 2021 sorry my attention got stuck on the singleton.
- user1234 (7/49) Sep 01 2021 sorry there was a format mistake not detected at compile time.
- james.p.leblanc (15/21) Sep 01 2021 ```
Dear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) In the example, there are two plots calls: 1) First, call is made using the object member function "gp.plot(x, etc.)" 2) The second uses a wrapper to allow use of the UFCS (uniform function call syntax) The ability to use the UFCS has the usual UFCS advantages, additionally the coder doesn't need to care about the actual name of the object's instantiation. **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** **Is there a more elegant way to do this?** First, the module: ------------------------------------------------------------------ module gnuplot_mod; import std.stdio; import std.process; import std.conv : to; class Gnuplot { // modification of wiki.dlang.org/Low-Lock_Singleton_Pattern ProcessPipes pipe; private this() { this.pipe = pipeProcess("/usr/local/bin/gnuplot") ; } private static bool instantiated_; private __gshared Gnuplot instance_; static Gnuplot get() { if (!instantiated_) { synchronized(Gnuplot.classinfo) { if (!instance_) { instance_ = new Gnuplot(); } instantiated_ = true; } } return instance_; } void cmd(string txt) { this.pipe.stdin.writeln(txt); this.pipe.stdin.flush(); return; } void plot(double[] x, string txt = "ls 21 lw 2"){ this.pipe.stdin.writeln("plot '-' u 1:2 with lines " ~ txt); foreach( ind, val ; x) this.pipe.stdin.writeln( to!string(ind) ~ " " ~ to!string(val) ); this.pipe.stdin.writeln("e"); this.pipe.stdin.flush(); } } void cmd(string txt){ Gnuplot gp; gp = gp.get(); gp.cmd(txt); } void plot(double[] x, string txt){ Gnuplot gp; gp = gp.get(); gp.plot(x, txt); } --------------------------------------------------------------- Now, the main ... --------------------------------------------------------------- import gnuplot_mod; import std.stdio; void main(){ Gnuplot gp; gp = gp.get(); double[] x = [1.1, 0.2, 3.1, 2.2, 3.1, 0.6]; double[] y = [-1.1, 0.2, -3.1, 2.2, 3.1, -0.6]; writeln("\nusing singleton's member functions: plot and cmd"); gp.plot(x, "ls 31 lw 3"); gp.cmd("pause 2"); writeln("\nusing uniform function call syntax (UFCS): plot and cmd"); y.plot("ls 41 lw 8"); cmd("pause 2"); } Any suggestions on a better way are greatly appreciated. Best Regards, James
Sep 01 2021
On Wednesday, 1 September 2021 at 16:02:47 UTC, james.p.leblanc wrote:Dear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) [...] **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** [...] Any suggestions on a better way are greatly appreciated. Best Regards, Jameshello, I'd suggest this: ```d shared static this() { get(); // cache instance before main(){} // to get rid of the synchronized() stmt } static Gnuplot get() { __gshared Gnuplot instance; return instance ? instance : (instance = new Gnuplot()); } ```
Sep 01 2021
On Wednesday, 1 September 2021 at 19:54:14 UTC, user1234 wrote:On Wednesday, 1 September 2021 at 16:02:47 UTC, james.p.leblanc wrote:user1234, Thanks for your reply, I will need to look at it deeper. I also realize that my post was not so clear, to clarify: I needed to implement two wrapper functions ... that are **in** the module, but **outside** of the object, copied below: **void cmd(string txt){** **Gnuplot gp;** **gp = gp.get();** **gp.cmd(txt);** **}** **void plot(double[] x, string txt){** **Gnuplot gp;** **gp = gp.get();** **gp.plot(x, txt);** **}** These enable use of the UFCS in main() (without prefixing with instantiated object's name **gp** ). The gp prefix only needs to be in these wrappers that exist in the module, not in the main(). The question is if there is a way to enable UFCS without such wrapper (see example in main() in original posting). Thanks again, and now I need to play a bit with your suggestion to learn from it. Best Regards, JamesDear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) [...] **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** [...] Any suggestions on a better way are greatly appreciated. Best Regards, Jameshello, I'd suggest this: ```d shared static this() { get(); // cache instance before main(){} // to get rid of the synchronized() stmt } static Gnuplot get() { __gshared Gnuplot instance; return instance ? instance : (instance = new Gnuplot()); } ```
Sep 01 2021
On Wednesday, 1 September 2021 at 20:59:15 UTC, james.p.leblanc wrote:[...] The question is if there is a way to enable UFCS without such wrappersorry my attention got stuck on the singleton. So my suggestion is rather to only enable the ufcs style. This highlights the fact that the class is useless, you can use a simple getter that initializes a hidden global: ```d module gnuplot_mod; import std.stdio; import std.process; import std.algorithm : each; import std.range : enumerate; ProcessPipes gnuplot () { __gshared ProcessPipes pipe; return pipe.pid ? pipe : (pipe = pipeProcess("/usr/local/bin/gnuplot")); } static void cmd(string txt) { with (gnuplot()) { stdin.writeln(txt); stdin.flush(); } } static void plot(double[] x, string txt = "ls 21 lw 2"){ with (gnuplot()) { stdin.writeln("plot '-' u 1:2 with lines ", txt); enumerate(x).each!((i,v) => stdin.writefln!"%s %f"(i, v))(); stdin.writeln("e"); stdin.flush(); } } void main() { double[] x = [1.1, 0.2, 3.1, 2.2, 3.1, 0.6]; double[] y = [-1.1, 0.2, -3.1, 2.2, 3.1, -0.6]; y.plot("ls 41 lw 8"); cmd("pause 2"); } ```
Sep 01 2021
On Wednesday, 1 September 2021 at 22:01:12 UTC, user1234 wrote:On Wednesday, 1 September 2021 at 20:59:15 UTC, james.p.leblanc wrote:sorry there was a format mistake not detected at compile time. ```diff - enumerate(x).each!((i,v) => stdin.writefln!"%s %f"(i, v))(); + enumerate(x).each!(a => stdin.writefln!"%s %f"(a.index, a.value))(); ```[...] The question is if there is a way to enable UFCS without such wrappersorry my attention got stuck on the singleton. So my suggestion is rather to only enable the ufcs style. This highlights the fact that the class is useless, you can use a simple getter that initializes a hidden global: ```d module gnuplot_mod; import std.stdio; import std.process; import std.algorithm : each; import std.range : enumerate; ProcessPipes gnuplot () { __gshared ProcessPipes pipe; return pipe.pid ? pipe : (pipe = pipeProcess("/usr/local/bin/gnuplot")); } static void cmd(string txt) { with (gnuplot()) { stdin.writeln(txt); stdin.flush(); } } static void plot(double[] x, string txt = "ls 21 lw 2"){ with (gnuplot()) { stdin.writeln("plot '-' u 1:2 with lines ", txt); enumerate(x).each!((i,v) => stdin.writefln!"%s %f"(i, v))();stdin.writeln("e"); stdin.flush(); } } void main() { double[] x = [1.1, 0.2, 3.1, 2.2, 3.1, 0.6]; double[] y = [-1.1, 0.2, -3.1, 2.2, 3.1, -0.6]; y.plot("ls 41 lw 8"); cmd("pause 2"); } ```
Sep 01 2021
On Wednesday, 1 September 2021 at 22:11:29 UTC, user1234 wrote:On Wednesday, 1 September 2021 at 22:01:12 UTC, user1234 wrote:`````` user1234, Thanks! This is perfect, getting rid of the class altogether. Yes, as pointed out in your response, that class was rather useless. (For some unknown reason, I had been stuck on creating a singleton to avoid multiple gnuplot processes -- very unnecessary as I now see.). The ternary operator with the pipe id is much cleaner and leaner. Thanks again, for your time, energy and insight. Best Regards, JamesProcessPipes gnuplot () { __gshared ProcessPipes pipe; return pipe.pid ? pipe : (pipe = pipeProcess("/usr/local/bin/gnuplot")); }
Sep 01 2021