Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enum instances aren't singletons #8

Open
hikari-no-yume opened this issue Jan 22, 2015 · 16 comments
Open

Enum instances aren't singletons #8

hikari-no-yume opened this issue Jan 22, 2015 · 16 comments

Comments

@hikari-no-yume
Copy link

Ideally, SomeEnum::Foo() should always return the same instance of SomeEnum, so you can do $someEnumValue1 === SomeEnum::Foo() instead of $someEnumValue1->getValue() !== SomeEnum::Foo

@mnapoli
Copy link
Member

mnapoli commented Jan 30, 2015

Yes that's really something I'd like to have!

Maybe a 2.0 version could make the constructor private? Currently there is a "cache" so that MyEnum::FOO() always returns the same object, the only problem is that users can still do new MyEnum(MyEnum::FOO)

But then what about deserialized enums…

@hikari-no-yume
Copy link
Author

Oh, deserialisation would be an issue :/

Also, I discovered that I may just be able to use == as it does structural comparison.

@mnapoli
Copy link
Member

mnapoli commented Jan 30, 2015

yep forgot to mention that, I use == too.

@adrium
Copy link

adrium commented Jan 21, 2017

See #43 or adrium/php-enum version 1.5.1

@shadowhand
Copy link

What would be the point of singletons? Enums are value objects and value objects equality is not based on identity:

a value object is a small object that represents a simple entity whose equality is not based on identity

The current implementation of Enum is correct because it contains an equals() method that tests equality based on type and value.

@mnapoli
Copy link
Member

mnapoli commented May 7, 2018

@shadowhand that's a good point indeed. I think the main "issues" would be practicality (ability to use ===) and performances.

But this package has worked fine until now without singletons, a 2.0 would create a lot of conflicts downstream for very little gain so I think it's acceptable to keep this on hold unless we find a very good reason to release a v2.0.

@KartaviK
Copy link
Contributor

Constructor is public, so it will automatically create new instance.
To use singletons, you can use search method, like this:

$singletone = MyEnum::{MyEnum::search($value)}();

Not best practice, but it will always create single instance

@shadowhand
Copy link

shadowhand commented Apr 10, 2019

@KartaviK see my response above. Enums (as implemented in this package) are value objects, and value objects have equality by state, not by being singletons.

@dbalabka
Copy link

Creating a new object for each enum usage is memory wasting. Imagine you are fetching a huge amount of rows from the database. High memory usage affects performance in general (e.g. GC).

Comparing the other languages implementations you can see that they use the singletons:

  1. Python https://repl.it/@torinaki/Python-Enum-is-Singleton
  2. Java https://repl.it/@torinaki/Java-Enum-is-Singleton

@githoober
Copy link

What would be the point of singletons? Enums are value objects and value objects equality is not based on identity:

a value object is a small object that represents a simple entity whose equality is not based on identity

The current implementation of Enum is correct because it contains an equals() method that tests equality based on type and value.

IMO, the way this library instantiates its enum values is a detail of implementation. If you disagree, then this library should clearly state in its description that it relies on the value object definition of object equality.

@dbalabka
Copy link

I support @githoober. IMO it leads to misunderstanding. Enums and ValueObjects behave differently. Enums (as I showed in a comment above) in most languages represents the set of constants. In turn, ValueObject is a structure that can be instantiated (!) with any set of values for defined parameters.

@dbalabka
Copy link

dbalabka commented Sep 8, 2019

I came to a conclusion, that It'll require several BC breaks and would be problematic to implement in this library in the near future.

As a result, I have created my own implementation of Enums:
https://github.com/dbalabka/php-enumeration

The implementation is based on Enumeration Classes and is very close to Java Enums and Python Enums.
In the end, I realize that Enumeration Classes address a bunch of other open issues sitting in the backlog:

  1. Enum instances aren't singletons #8 - all enums are singletons. Also, I have provided the workaround for serialization issue
  2. Add support for phpstorm #99 - the autocompletion isn't a problem anymore due to the static properties has been employed instead of magic methods.
  3. Most methods do not consider constants with same values. #65, Constant value can be a array #53 - developer can customize the Enum element instantiation and provide any type and count of parameters into the constructor (e.g. arrays, duplicated values)
  4. Value-less enum #7 - the value can be omitted to create simple named Enum

@fruit
Copy link

fruit commented Sep 17, 2019

Please, don't do it (i.e. put enums into singletons). Enums are a value objects, and this is bad idea to have singletons for value object. In normal languages to compare value objects you have to implement ->equals() method on it to make comparisons (thanks, current Enum class already have it).

@dbalabka
Copy link

@fruit thank you for your opinion. As I showed in a comment above, Java and Python use an exactly single object instance to represent Enum value.
There is also a great answer on StackOverflow that explains how ->equals() works in Java and what relation Enum has to a singleton.
Please correct me if I'm mistaken somewhere.

@alexkuc
Copy link

alexkuc commented Jul 10, 2021

I think it would help to mention in README.md that strict comparison won't work as expected (b/c it is not mentioned that php-enum is not singleton) and that there are 2 workarounds:

  1. weak comparison i.e. ==
  2. method ->equals()

@mnapoli
Copy link
Member

mnapoli commented Jul 12, 2021

@alexkuc sure that makes sense, feel free to send a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants