Skip to content

An extensible way to have an "enum class" through different languages

License

Notifications You must be signed in to change notification settings

joooKiwi/enumeration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Enumeration

This project is made to have an implementation of enum class similar in each language. Or at least give a similar behaviour.


Also, the implementations use class inheritance in the `Enum` as well as their `CompanionEnum` counterpart.

The only location where it doesn't follow this is in the utility classes / files like EnumHelper, EnumConstants and EnumExtension.

Implementation by language

Note: The usage of COMPANION_ENUM in the extension can be changed to CompanionEnum, CompanionEnumWithParent, CompanionEnumWithGrandParent or CompanionEnumWithGreatGrandParent. And in C#, it uses the type system to its advantage (like for the ValueTuple).

Language Published class
extension
native
enum
functionality
trait
usage
annotation / attribute utility
Javascript
Typescript
version
downloads
yes EnumConstant
Java Maven (in progress) yes yes yes EnumHelper, EnumConstant, EnumMethods
Kotlin Maven (in progress) yes yes yes EnumConstant, EnumExtension
PHP Composer not necessary not necessary yes yes EnumHelper, EnumConstant EnumMethods
C# Nuget yes yes yes EnumHelper, EnumConstant, EnumExtension

(This may change once the implementation is made)

Related projects

Here is a list of the related projects made by me

Contribution

You can contribute to my projects in 2 different ways

Implementation by language

The implementations are different across the different languages, but they should not change in their implementation (it's only the syntax that is different for the most part).

Javascript and Typescript implementation

This project (currently published on NPM) is the one with the most manual labour to implement.

The basic usage can be:

Enum extension

Keep in mind that the Enumerable interface can also be used if the direct inheritance cannot be used. But a custom implementation is required for them.

// Javascript
class Example extends Enum {}
// Typescript (generic usage)
class Example extends Enum {}
// Typescript (strict types)
class Example extends Enum<Ordinals, Names> {}
// Typescript (strict specific types)
class Example<ORDINAL extends Ordinals = Ordinals, NAMES extends Names = Names,> extends Enum<ORDINAL, NAME> {}
Companion enum

The companion enum implementation is a static field on the enum class named CompanionEnum due to the fact there is no Annotation/Attribute usable in the language natively.

And in the case a custom implementation is needed, the classes are extensible. Also, there is interfaces like CompanionEnumDeclaration should be declared.

// Javascript
class CompanionEnum_Example extends CompanionEnum {
    static #instance
    /** @private */constructor() { super(Example,) }
    static get get() { return CompanionEnum_Example.#instance ??= new CompanionEnum_Example() }
}
// Typescript (generic usage)
class CompanionEnum_Example extends CompanionEnum {
    static #instance?: CompanionEnum_Example
    private constructor() { super(Example,) }
    public static get get() { return CompanionEnum_Example.#instance ??= new CompanionEnum_Example() }
}
// Typescript (strict type usage)
class CompanionEnum_Example extends CompanionEnum<Example, typeof Example> {
    static #instance?: CompanionEnum_Example
    constructor() { super(Example,) }
    static get get() { return CompanionEnum_Example.#instance ??= new CompanionEnum_Example() }
}
Parenting enum enum

Implementing the enum with a "kind-of" inheritance can be used through the usage of get parent, get grandParent and get greatGrandParent.

Javascript
class EnumExample extends Enum {}

class NullableParentingEnumExample extends EnumWithNullableParent {}
class ParentingEnumExample extends EnumWithParent {}

class NullableGrandParentingEnumExample extends EnumWithNullableGrandParent {}
class GrandParentingEnumExample extends EnumWithGrandParent {}

class NullableGreatGrandParentingEnumExample extends EnumWithNullableGreatGrandParent {}
class GreatGrandParentingEnumExample extends EnumWithGreatGrandParent {}
Typescript
class EnumExample extends Enum {}

class NullableParentingEnumExample extends EnumWithNullableParent<EnumExample> {}
class ParentingEnumExample extends EnumWithParent<EnumExample> {}

class NullableGrandParentingEnumExample extends EnumWithNullableGrandParent<EnumExample, NullableParentingEnumExample> {}
class GrandParentingEnumExample extends EnumWithGrandParent<EnumExample, ParentingEnumExample> {}

class NullableGreatGrandParentingEnumExample extends EnumWithNullableGreatGrandParent<NullableGrandParentingEnumExample, NullableParentingEnumExample, EnumExample> {}
class GreatGrandParentingEnumExample extends EnumWithGreatGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {}
Parenting companion extension

The parent companion enum do use inheritance, but not the direct inheritance.

Meaning that if Enum1 has a parent field Enum2. Enum2 cannot receive a Enum1 through its companion enum, but the opposite is possible. Enum1 can receive a Enum2 through its companion enum.

Javascript
class CompanionEnum_EnumExample extends CompanionEnum {
    static #instance
    constructor() { super(EnumExample,) }
    static get get() { CompanionEnum_EnumExample.#instance ??= new CompanionEnum_EnumExample() }
}
class CompanionEnum_ParentingEnumExample extends CompanionEnumWithParent {
    static #instance
    constructor() { super(EnumExample, ParentingEnumExample,) }
    static get get() { CompanionEnum_ParentingEnumExample.#instance ??= new CompanionEnum_ParentingEnumExample() }
}
class CompanionEnum_GrandParentingEnumExample extends CompanionEnumWithGrandParent {
    static #instance
    constructor() { super(EnumExample, ParentingEnumExample, GrandParentingEnumExample,) }
    static get get() { CompanionEnum_GrandParentingEnumExample.#instance ??= new CompanionEnum_GrandParentingEnumExample() }
}
Typescript
class CompanionEnum_EnumExample extends CompanionEnum<EnumExample, typeof EnumExample> {
    static #instance?: CompanionEnum_EnumExample
    private constructor() { super(EnumExample,) }
    public static get get() { CompanionEnum_EnumExample.#instance ??= new CompanionEnum_EnumExample() }
}
class CompanionEnum_ParentingEnumExample extends CompanionEnumWithParent<EnumExample, typeof EnumExample, ParentingEnumExample, typeof ParentingEnumExample> {
    static #instance?: CompanionEnum_ParentingEnumExample
    private constructor() { super(EnumExample, ParentingEnumExample,) }
    public static get get() { CompanionEnum_ParentingEnumExample.#instance ??= new CompanionEnum_ParentingEnumExample() }
}
class CompanionEnum_GrandParentingEnumExample extends CompanionEnumWithGrandParent<EnumExample, typeof EnumExample, ParentingEnumExample, typeof ParentingEnumExample, GrandParentingEnumExample, typeof GrandParentingEnumExample> {
    static #instance?: CompanionEnum_GrandParentingEnumExample
    private constructor() { super(EnumExample, ParentingEnumExample, GrandParentingEnumExample,) }
    public static get get() { CompanionEnum_GrandParentingEnumExample.#instance ??= new CompanionEnum_GrandParentingEnumExample() }
}

It also uses utility classes like the internal Helper and the public EnumConstants in order to be accessible outside the scope of the enums.

Java implementation

This implementation does work independently of the Kotlin implementation. Meaning that a enum class in Kotlin would not work with a enum in Java. But an adaptor could be used in these cases. Also, if you intend to use this implementation with Kotlin directly, then use the Kotlin implementation since it is more optimized for it.

Simple example
import github.io.joookiwi.java.enumerable.Enumerable;
enum Example implements Enumerable<Example> {}
import github.io.joookiwi.java.enumerable.Enum;
class Example extends Enum<Example> {}
Parenting enum

You can use the interface directly when implementing the enum directly

import github.io.joookiwi.java.enumerable.Enumerable;
enum EnumExample implements Enumerable<EnumExample> {}
import github.io.joookiwi.java.enumerable.EnumerableWithParent;
import org.jetbrains.annotations.Nullable;
enum ParentingEnumExample
    implements EnumerableWithParent<EnumExample> {

    private final EnumExample parent;
    ParentingEnumExample() { this(null); }
    ParentingEnumExample(@Nullable EnumExample parent) { this.parent = parent; }
    @Override public final @Nullable EnumExample getParent() { return parent; }

}
import github.io.joookiwi.java.enumerable.EnumerableWithGrandParent;
import org.jetbrains.annotations.Nullable;
enum GrandParentingEnumExample
    implements EnumerableWithGrandParent<EnumExample, ParentingEnumExample> {

    private final ParentingEnumExample parent;
    private final EnumExample grandParent;
    GrandParentingEnumExample() { this(null, null); }
    GrandParentingEnumExample(@Nullable ParentingEnumExample parent) { this(parent, null); }
    GrandParentingEnumExample(@Nullable ParentingEnumExample parent, @Nullable EnumExample grandParent) {
        this.parent = parent;
        this.grandParent = grandParent;
    }
    @Override public final @Nullable ParentingEnumExample getParent() { return parent; }
    @Override public final @Nullable EnumExample getGrandParent() { return grandParent; }

}

Or you can use the "indirect" inheritance when using a class.

Of course, the interface is still possible, but less recommended.

import github.io.joookiwi.java.enumerable.Enum;
class EnumExample extends Enum<EnumExample> {

    private EnumExample() { super(); }

}
import github.io.joookiwi.java.enumerable.EnumeWithParent;
import org.jetbrains.annotations.Nullable;
class ParentingEnumExample
    extends EnumWithParent<ParentingEnumExample, EnumExample> {

    private ParentingExample() { super(); }
    private ParentingExample(EnumExample parent) { super(parent); }

}
import github.io.joookiwi.java.enumerable.EnumWithGrandParent;
import org.jetbrains.annotations.Nullable;
class GrandParentingEnumExample
    extends EnumeWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {

    private ParentingExample() { super(); }
    private ParentingExample(@Nullable ParentingEnumExample parent) { super(parent); }
    private ParentingExample(@Nullable ParentingEnumExample parent, @Nullable EnumExample grandParent) { super(parent, grandParent); }

}

Kotlin implementation

This implementation does work independently of the Java implementation. Meaning that a enum in Java would not work with a enum class in Kotlin. But an adaptor could be used in these cases. Also, if you intend to use this implementation with Java directly, then use the Java implementation since it is more optimized for it.

Simple example
enum Example {}
import org.github.joookiwi.kotlin.enumerable.Enum
class Example: Enum()
Parenting enum

You can use the interface directly when implementing the enum directly

import org.github.joookiwi.kotlin.enumerable.Enumerable
enum EnumExample: Enumerable<EnumExample>
import org.github.joookiwi.kotlin.enumerable.EnumerableWithParent
enum ParentingEnumExample(
    override val parent: EnumExample? = null,
): EnumerableWithParent<ParentingEnumExample, EnumExample>
import org.github.joookiwi.kotlin.enumerable.EnumerableWithGrandParent
enum GrandParentingEnumExample(
    override val parent: ParentingEnumExample? = null,
    override val grandParent: EnumExample? = null,
): EnumerableWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample>

Or you can use the "indirect" inheritance when using a class.

Of course, the interface is still possible, but less recommended.

import org.github.joookiwi.kotlin.enumerable.Enum
class EnumExample: Enum<EnumExample>()
import org.github.joookiwi.kotlin.enumerable.EnumWithParent
class ParentingEnumExample(
    override val parent: EnumExample? = null,
): EnumWithParent<ParentingEnumExample, EnumExample>(parent)
import org.github.joookiwi.kotlin.enumerable.EnumWithGrandParent
class GrandParentingEnumExample(
    override val parent: ParentingEnumExample? = null,
    override val grandParent: EnumExample? = null,
): EnumWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample>(parent, grandParent)

PHP implementation

This implementation is only in a concept phase. It may change at any time depending on how it can really be used in PHP.

Simple example
use joookiwi\enumerable\EnumerableTrait;
enum Example {
    use EnumerableTrait<Example>;
}
use joookiwi\enumerable\Enum;
class Example extends Enum<Example> {}
Parenting enum

Since the PHP implementation is only in concept phase, this part may be incomplete or not compilable.

But you can use the "indirect" inheritance when using a class.

use joookiwi\enumerable\Enum;
class EnumExample extends Enum<EnumExample> {

    private function __construct() { parent::__construct(); }

}
use joookiwi\enumerable\EnumeWithParent;
class ParentingEnumExample
    extends EnumWithParent<ParentingEnumExample, EnumExample> {

    private function __construct(parent: EnumExample|null = null) { parent::__construct(parent); }

}
use joookiwi\enumerable\EnumWithGrandParent;
class GrandParentingEnumExample
    extends EnumeWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {

    private ParentingExample(ParentingEnumExample|null parent = null, EnumExample|null grandParent = null) { parent::__construct(parent, grandParent); }

}

C# implementation

This implementation is only in a concept phase, but it has great features to use. Keep in mind that extension function can be used for the already existing enums. It may change at any time depending on how it can really be used in C#.

Simple example
enum Example {}
using joookiwi.enumerable;
class Example: Enum<Example> {}
Parenting enum

Or you can use the "indirect" inheritance when using a class.

Of course, the interface is still possible, but less recommended.

using joookiwi.enumerable;
class EnumExample: Enum<EnumExample> {

    private EnumExample(): base() {}

}
using joookiwi.enumerable;
class ParentingEnumExample:
    Enum<ParentingEnumExample, EnumExample?> {

    private ParentingExample(): base() {}
    private ParentingExample(EnumExample? parent): base(parent) {}

}
using joookiwi.enumerable;
class GrandParentingEnumExample:
    Enum<GrandParentingEnumExample, ParentingEnumExample?, EnumExample?> {

    private ParentingExample(): base() {}
    private ParentingExample(ParentingEnumExample? parent): base(parent) {}
    private ParentingExample(ParentingEnumExample? parent, EnumExample? grandParent): base(parent, grandParent) {}

}

And the non-nullable can be used instead

using joookiwi.enumerable;
class ParentingEnumExample:
    Enum<ParentingEnumExample, EnumExample> {

    private ParentingExample(): base() {} // This will throw an exception
    private ParentingExample(EnumExample parent): base(parent) {}

}
using joookiwi.enumerable;
class GrandParentingEnumExample:
    Enum<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {

    private ParentingExample(t): base() {} // This will throw an exception
    private ParentingExample(ParentingEnumExample parent): base(parent) {} // This will throw an exception
    private ParentingExample(ParentingEnumExample parent, EnumExample grandParent): base(parent, grandParent) {}

}

Version history

JS / TS version Date Quick note
3.10.0 August 12th, 2025 collection (1.12.01.13.0)
3.9.0 January 8th, 2025 2025 update,
collection (1.11.31.12.0)
3.8.2 December 12th, 2024 collection (1.11.21.11.3)
3.8.1 November 19th, 2024 collection (1.11.11.11.2)
3.8.0 November 7th, 2024 collection (1.10.01.11.1)
3.7.0 October 8th, 2024 collection (1.9.31.10.0)
3.6.3 August 15th, 2024 collection (1.9.21.9.3)
3.6.2 July 23rd, 2024 collection (1.9.11.9.2)
3.6.1 July 21st, 2024 collection (1.9.01.9.1)
3.6.0 July 21st, 2024 collection (1.8.01.9.0)
3.5.0 March 31st, 2024 Addition of type to the dependency,
Update to the documentation across the project,
Addition of some future plan
3.4.0 February 19th, 2024 2024 update,
Formatting across the whole project,
collection (1.6.11.7.0)
3.3.1 December 23rd, 2023 collection (1.6.01.6.1)
3.3.0 December 4th, 2023 collection (1.5.01.6.0)
3.2.0 September 28th, 2023 collection (1.4.01.5.0),
Change of the exception hierarchy to be only toward the Javascript instead of Java-like
3.1.0 September 8th, 2023 collection (1.3.01.4.0)
3.0.0 August 14th, 2023 Big changes to make the CompanionEnum more extensible via its protected methods
2.7.0 July 27th, 2023 collection (1.1.01.2.0)
2.6.1 July 26th, 2023 Fix on the [Symbol.iterator]() that gave an error since it uses the yield*
2.6.0 July 23rd, 2023 collection (1.0.41.1.0)
2.5.1 July 14th, 2023 The file EnumHelper was not exported
2.5.0 July 14th, 2023 New Enum inheritor were added (parent, grandparent and great-grandparent with their nullable counterpart),
Relocation & separation of the helper methods in its own folder
2.4.2 July 4th, 2023 The file EnumHelper was exported as a type instead of directly
2.4.1 July 4th, 2023 The files were not exported in the index file
2.4.0 July 3rd, 2023 The dependency of collection is now a standalone package
2.3.0 June 18th, 2023 New and renaming of some methods in collection (see the release note)
2.2.3 June 13th, 2023 Fix on the collection when receiving receiving a Set or Array of 1
2.2.2 June 12th, 2023 Fix on the reverse order of the enum fields initialization
2.2.1 June 12th, 2023 Fix of this[0] not set when receiving an array of 1
2.2.0 June 12th, 2023 New join, toWeakSet, reverse & hasNull in collection
2.1.1 June 8th, 2023 Fix on the package.json file
2.1.0 June 6th, 2023 Change from absolute imports to relative one (for better dependant utilisation)
2.0.0 February 2nd, 2023 Change from static methods implementation to a companion enum implementation
1.2.0 Novembre 20th, 2022 New filterByIndex & find in collection
1.1.0 November 19th, 2022 New has, join, filter in the collection
1.0.6 November 12nd, 2022 Addition of some forgotten types to be exported
1.0.5 November 11st, 2022 The first version (after few tentative of publishing it)

About

An extensible way to have an "enum class" through different languages

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published