News for hackers. Stuff that matters.
Re:“Design Patterns” Aren't (2002) by matheusmoreira on Sunday March 07, 2021 @03:20PM (#26379404)
The best explanation I've ever seen for design patterns is that they are workarounds for weaknesses of the programming language. Usually Java and its contemporaries.

http://journal.stuffwithstuff.com/2010/09/18/futureproofing-...

Factories, for example. They're essentially just constructors. So why not use the new keyword? Turns out new has limitations:

  - Dependency on the constructed type at the ABI level
  - Cannot return subtypes of the constructed type
  - Special keyword, not orthogonal with the rest of the language
Singletons, for example. They're essentially classes with static methods and state. Why not use these language features instead of coming up with incredibly convoluted ways to ensure only a single instance of an object has been created? Turns out classes have limitations:

  - Classes aren't objects
  - Classes cannot be passed as parameters
  - Classes cannot implement interfaces
The need for all of these patterns simply disappears in a better designed language. In Ruby for example everyone uses factory methods without even realizing it and classes are fully featured objects that can be used in any context.
Re:“Design Patterns” Aren't (2002) by catlifeonmars on Sunday March 07, 2021 @06:04PM (#26380666)
Interestingly enough, the same phenomenon arises in languages with fewer features. In go, for example, there are no constructors, only functions that return structs. Singletons are just global variables referencing a struct, etc etc.
Re:“Design Patterns” Aren't (2002) by commandlinefan on Sunday March 07, 2021 @06:20PM (#26380754)
Every programming language has “singletons”: they’re just global variables.
Re:“Design Patterns” Aren't (2002) by wruza on Sunday March 07, 2021 @07:57PM (#26381307)
Singleton’s main feature is not that it is globally accessible, but in that it represents a state that cannot be naturally duplicated. The pattern itself lies in a controlled instantiation, where a method/constructor/factory returns a cached value on a second call. Globals are just that – globals.
Re:“Design Patterns” Aren't (2002) by bvrmn on Sunday March 07, 2021 @08:18PM (#26381420)
Global variable is naturally can't be duplicated. Or do you assume dark corners of initialization spec for c++?
Re:“Design Patterns” Aren't (2002) by AnimalMuppet on Sunday March 07, 2021 @09:02PM (#26381654)
At global level:

   ThingThereCanBeOnlyOneOf a;
   ThingThereCanBeOnlyOneOf b;
Oops. That's not a singleton. That depends on nobody, ever, anywhere in the code creating another one. In contrast, a true singleton can enforce that there is only one, no matter what the callers do.
Re:“Design Patterns” Aren't (2002) by wott on Sunday March 07, 2021 @09:21PM (#26381762)
Globals like a and b are fields of the singleton, not instance of singleton(s). The global space is the singleton (or a juxtaposition of singletons, if we let aside the lack of visibility protection), and global variables and functions are the fields (members) and the methods of the singleton.
Re:“Design Patterns” Aren't (2002) by AnimalMuppet on Sunday March 07, 2021 @09:26PM (#26381780)
You can look at it that way, I suppose, though I consider it to be a fairly odd perspective. But it doesn't help at all with the problem of enforcing that there be only one ThingThereCanBeOnlyOneOf. Therefore globals are not a true solution to the problem that singletons are trying to solve.
Re:“Design Patterns” Aren't (2002) by bcrosby95 on Sunday March 07, 2021 @10:33PM (#26382080)
Just use static methods.
Re:“Design Patterns” Aren't (2002) by candiodari on Tuesday March 09, 2021 @07:06AM (#26398032)
Singletons solve several problems with static methods, namely that you can't change their behavior (e.g. do error logging to both the global error log and a per-request log, then at other times do it to a log buffer for testing, and NOT to anywhere else).

At least with a singleton you can create a bunch of "standard configurations" by calling them with a different constructor at startup time. So you can have a test DB during tests, different log targets, read from different filesystem (not the real one, but the one in the testdata/ directory) ...

Better yet is to have a "context" abstraction that you pass down the chain. Issue with that is, every method needs to have a first parameter that is the context ... so it requires some discipline.

Some frameworks (java @#$@#%@# servlet spec for example) make this parameter implicit and then use something akin to exception resolution to get this parameter (so when you do GetContext(), it unwinds the stack to give you the correct context). That makes things very complicated, and is an invisible LOT of state that gets passed down the stack. Still better than singletons or static methods, but good luck figuring out why a context is set to X.

In all cases you need to be very careful to USE the context. DO NOT use database except the one in the context, no caches except the one in the context, no filesystem reading, logging, ... except by redirecting through the context.

Re:“Design Patterns” Aren't (2002) by bvrmn on Tuesday March 09, 2021 @01:34AM (#26396055)
I can also get second instance with singleton. In reality singleton doesn't enforce anything. It's a only a convenient way to make global scope in inconvenient languages.
Re:“Design Patterns” Aren't (2002) by AtomicPlayboy on Sunday March 07, 2021 @09:30PM (#26381802)
I would partially agree, although I don't know many implementations.

It's a state that cannot be naturally duplicated, alright, a "single source of truth". But lazy instantiation is nothing more than a very important and very common second. The pattern itself lies in preventing public-level instantiation (i.e. in Java it could translate to a class with a private constructor, private instantiation and access to the instance through a class-level/static getter, and also making it a final class).

Re:“Design Patterns” Aren't (2002) by virtue3 on Sunday March 07, 2021 @10:07PM (#26381961)
my (very tongue in cheek) favorite description of singletons - an object oriented way to break object orientedness.
Re:“Design Patterns” Aren't (2002) by dwaite on Sunday March 07, 2021 @10:26PM (#26382043)
Not quite - variables are references to objects, there's nothing that restricts global variables themselves to only reference a single _instance_ of an object.

That said, a global singleton (and global state in general) is usually an anti-pattern; having pretty much any code be able to depend on the state makes it very difficult to evaluate the impact of a change.

Re:“Design Patterns” Aren't (2002) by galaxyLogic on Monday March 08, 2021 @12:22AM (#26382523)
> - Classes aren't objects

Right. Except in Smalltalk they are

Re:“Design Patterns” Aren't (2002) by grzm on Monday March 08, 2021 @12:33AM (#26382579)
Ruby, too, IIRC. And likely others.
Re:“Design Patterns” Aren't (2002) by kitkat_new on Sunday March 07, 2021 @06:28PM (#26380808)
is the Abstract Factory showing a weakness of all languages in which it is useful? What is the underlying weakness?
Re:“Design Patterns” Aren't (2002) by anonymoushn on Sunday March 07, 2021 @10:01PM (#26381934)
The question is, "I have some code that wants to make some different kinds of a thing in the same way, then use the different kinds in the same way, being unaware that they are different and not depending on any particular kind. How?" The answer is typically that you can pass a function to that code which accepts some stuff and returns the thing it is concerned with. You may say "Thats an Abstract Factory" but when we write like 4 LoC instead of 3 classes in different files we often don't feel a need to give it a name.

Edit: Also, depending on the circumstances, you can probably just pass the class or its constructor instead of passing a newly written function. That would get you down to ~0 LOC involved in replicating the functionality of this pattern.

Re:“Design Patterns” Aren't (2002) by anonymoushn on Monday March 08, 2021 @02:02AM (#26382958)
I guess if we want to get really abstract, we can say that the Abstract Factory pattern is a shim from a kind of late binding that is implemented in the language ("object orientation" a.k.a. dynamic dispatch on the first argument to a function) to one that is not (late binding of classes, constructors returning null, etc.). This isn't the whole picture though, because sometimes late binding isn't even an important part of what we're getting from the Abstract Factory pattern! For many use cases, we could imagine implementing the function that consumes the Abstract Factory using C++ templates or Zig comptime, and our compiler would generate separate subroutines for each factory type and statically determine which one to use at each call site and we would still be doing the Abstract Factory thing.

Another pattern called the Visitor Pattern is similarly a shim from dynamic dispatch on one argument to dynamic dispatch on two arguments. You just really hope you don't need dynamic dispatch on five arguments one day.