February 04, 2019
On Sunday, 3 February 2019 at 14:42:13 UTC, Ron Tarrant wrote:
> This morning I was Googling "singleton replacement" and someone on another forum said Factory would do the job. Anyone have thoughts on that?

It's usually replaced with inversion of control: the service instance is passed as an argument to object constructors, a related pattern is service provider when you need to access many services. Though it needs a more involved code organization compared to singleton. As for testing, singletons can be tested if you provide a setter method that allows to set a custom singleton instance.
February 04, 2019
On Saturday, 2 February 2019 at 16:56:45 UTC, Ron Tarrant wrote:
> Hi guys,
>
> I ran into another snag this morning while trying to implement a singleton. I found all kinds of examples of singleton definitions, but nothing about how to put them into practice.
>
> Can someone show me a code example for how one would actually use a singleton pattern in D? When I did the same thing in PHP, it took me forever to wrap my brain around it, so I'm hoping to get there a little faster this time.
>
> Here's the singleton code I've been playing with:
>
> class DSingleton
> {
> 	private:
> 	// Cache instantiation flag in thread-local bool
> 	// Thread local
> 	static bool instantiated_;
>
> 	// Thread global
> 	__gshared DSingleton instance_;
>
> 	this()
> 	{
> 		
> 	} // this()
>
> 	public:
> 	
> 	static DSingleton get()
> 	{
> 		if(!instantiated_)
> 		{
> 			synchronized(DSingleton.classinfo)
> 			{
> 				if(!instance_)
> 				{
> 					instance_ = new DSingleton();
> 					writeln("creating");
> 				}
>
> 				instantiated_ = true;
> 			}
> 		}
> 		else
> 		{
> 			writeln("not created");
> 		}
>
> 		return(instance_);
> 		
> 	} // DSingleton()
>
> } // class DSingleton
>
> So, my big question is, do I instantiate like this:
>
> DSingleton singleton = new DSingleton;
>
> Or like this:
>
> DSingleton singleton = singleton.get();
>
> And subsequent calls would be...? The same? Using get() only?

Your code is not going to work in the way you think.

Ex. you state "instantiated_" is thread-local but that's the flag you use to check whether it has been instantiated.

That will not work.

Instead it should actually be shared, especially because you use it in a synchronized statement.

Also:

DSingleton singleton = new DSingleton;

Defeats the purpose of singleton.
February 04, 2019
On Sunday, 3 February 2019 at 15:33:15 UTC, Russel Winder wrote:

> There is a lot of good stuff (both positive and negative) on Singleton here, but there is also a bit of prejudice and bigotry. Many of the links are worth looking through.
>
> https://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons

Thanks, Russell. I'll take a look.

> The good use case for Singleton is very rare, most people use them wrongly. It is all about eschewing all global state except when it is the one and only way of doing the design correctly. But then you have to use it correctly.

Yup. I've gone back and forth on usage, too. The cases I found for a Singleton ten years ago may have better solutions today. Like a command dispatcher, a configuration changes tracker, a keyboard pre-processor, an undo/redo stack, and the application itself.

> I currently have two Singletons in all my code, one I am trying to get rid of, the other is fair enough. I think, but I'd still like to get rid of it.

I'd be curious to hear what you have/will replace a singleton with.
February 04, 2019
On Sunday, 3 February 2019 at 18:53:10 UTC, Jacob Carlborg wrote:

> You don't need to make it so complicated. Here's a simpler example:

Excellent. Thank you. Simple is best.


>     private __gshared auto instance_ = new DSingleton;

My understanding is that in D, this line effectively says: the singleton is created at compile time and can't be changed, ever. Is that a fair assessment?

>
>     private this() // private to make sure no one else can create an instance

I've seen comments similar to this in several examples. When you say "no one else" you're personifying callers? And so this means: No caller outside the object? Which really amounts to: Since no one INside the object WILL call this() and no one OUTside CAN call this(), it won't ever get called.


>     writeln(DSingleton.instance);

No '()' needed for the call to DSingleton.instance?

If it's called again from somewhere else, say from within an object function several levels of scope away, it's called the same way?




February 04, 2019
On Sunday, 3 February 2019 at 22:25:18 UTC, Dejan Lekic wrote:

> I strongly suggest you find the thread started by Andrej Mitrovic many years ago. He compared several implementations of (thread-safe) singletons. I it an extremely helpful stuff, IMHO.

Thanks. I'll see if I can find it.
February 04, 2019
On Monday, 4 February 2019 at 10:36:49 UTC, Ron Tarrant wrote:
> On Sunday, 3 February 2019 at 18:53:10 UTC, Jacob Carlborg wrote:
>
>> You don't need to make it so complicated. Here's a simpler example:
>
> Excellent. Thank you. Simple is best.
>
>
>>     private __gshared auto instance_ = new DSingleton;
>
> My understanding is that in D, this line effectively says: the singleton is created at compile time and can't be changed, ever. Is that a fair assessment?
>

No, it can.

´´´
class DSingleton
{
    private __gshared auto instance_ = new DSingleton;
    size_t state;
    private this(){} // private to make sure no one else can create an instance
    static DSingleton instance() { return instance_; }
}

void main()
{
    assert(DSingleton.instance.state == 0);
    DSingleton.instance.state = 5;
    assert(DSingleton.instance.state == 5);
}
´´´

>>
>>     private this() // private to make sure no one else can create an instance
>
> I've seen comments similar to this in several examples. When you say "no one else" you're personifying callers?

To some extent...

> And so this means: No caller outside the object? Which really amounts to: Since no one INside the object WILL call this() and no one OUTside CAN call this(), it won't ever get called.

I think, what is meant is: The class has to be placed alone in a module so that no one outside the class (and the module) has any direct access to object creation routine.

>
>
>>     writeln(DSingleton.instance);
>
> No '()' needed for the call to DSingleton.instance?
>
> If it's called again from somewhere else, say from within an object function several levels of scope away, it's called the same way?

Yes. https://dlang.org/spec/function.html#optional-parenthesis
February 04, 2019
On 2019-02-04 11:36, Ron Tarrant wrote:

> I've seen comments similar to this in several examples. When you say "no one else" you're personifying callers? 

Yes.

> And so this means: No caller outside the object? Which really amounts to: Since no one INside the object WILL call this() and no one OUTside CAN call this(), it won't ever get called.

Yes, well it's called once. Technically since the protections in D work on module level a caller inside the same file can access the constructor. But one is usually in control of the whole file.

>>     writeln(DSingleton.instance);
> 
> No '()' needed for the call to DSingleton.instance?

No need. It's the way D to implement properties.

> If it's called again from somewhere else, say from within an object function several levels of scope away, it's called the same way?

You can call it with or without parentheses. It applies to all functions that don't take any arguments or functions taking a single argument and are called using UFCS [1].

[1] https://dlang.org/spec/function.html#pseudo-member

-- 
/Jacob Carlborg
February 05, 2019
On Monday, 4 February 2019 at 10:17:53 UTC, bauss wrote:
> On Saturday, 2 February 2019 at 16:56:45 UTC, Ron Tarrant wrote:

[...]

>> Here's the singleton code I've been playing with:
>>
[...]
>> 	static bool instantiated_;
>>
>> 	// Thread global
>> 	__gshared DSingleton instance_;
[...]
>> 		if(!instantiated_)
[...]
>> 				if(!instance_)

[...]

> Ex. you state "instantiated_" is thread-local but that's the flag you use to check whether it has been instantiated.

User angel has pointed to https://davesdprogramming.wordpress.com/ and the talk https://www.youtube.com/watch?v=ZHmIAdlNtiM which entails the reasoning about that pattern.

> That will not work.

Will it not work in therory (in which?) or in practice (in which)?

> Instead it should actually be shared, especially because you use it in a synchronized statement.

The purpose of the pattern is to avoid synchronisationin all but the first call to get().

> Also:
>
> DSingleton singleton = new DSingleton;
>
> Defeats the purpose of singleton.

Sure, but it is not lazy.


February 06, 2019
On Monday, 4 February 2019 at 19:23:26 UTC, Jacob Carlborg wrote:

> You can call it with or without parentheses. It applies to all functions that don't take any arguments or functions taking a single argument and are called using UFCS [1].
>
> [1] https://dlang.org/spec/function.html#pseudo-member

Okay, that explains a few things that I still hadn't caught onto. Thanks.
1 2 3
Next ›   Last »