In enums, its a convention to use SCREAMING_SNAKE_...
# naming
m
In enums, its a convention to use SCREAMING_SNAKE_CASE, which I totally agree with. However, in the process of making an enum typesafe, we have opted to rewrite it using sealed classes. Now, this sealed class with sealed children with objects is basically just a 'better' enum. writing the object with SCREAMING_SNAKE_CASE is not seen as best practice, but I feel like, in these cases, it should. Anyone agree/disagree?
j
I don’t use screaming with enum, pascal, which is accepted too.
m
Disagree, you should use the convention for object declarations, that is capitalized camel case. Btw, I can't understand your statement
in the process of making an enum typesafe
huh... what? Enum constants are already typesafe, what did you mean? 🤔
a
https://kotlinlang.org/docs/coding-conventions.html#property-names
For enum constants, it's OK to use either uppercase underscore-separated names (screaming snake case) (
enum class Color { RED, GREEN }
) or upper camel case names, depending on the usage.
I prefer UpperCamelCase everywhere because it's easier to migrate between enums and sealed types
👍 1
j
Indeed even it is not added to the convention yet, jetbrains and google are using pascal on constants too, so probably in the future screaming will "disappear"
m
@Matteo Mirk Lets say I have an enum called
Letter
the values for this letter are things like: A, B, C, D, E, and F these domains are being used throughout the entire application Now, I have different container classes and logic that should only work with
vowels
. I can introduce a 'isVowel' boolean on the enum. I also have different container classes and logic for things ending in the 'ee' sound; likewise, I can introduce a field for that. However, the specific combination of isVowel and isSoundE only occurs in some situations Lets say I have a function:
Copy code
fun shouldOnlyWorkWithVowels(example: VowelClassContainingTheField): String? {
	if(example.letter.isVowel){
		return when(example.letter){
			A -> example.aThing()
			E -> example.eThing()
			else -> error("this should never occur")
		}
	} else {
		return null
	}
}
If I make letter sealed with things like:
Copy code
sealed interface Letter
sealed interface Vowel : Letter
sealed interface SoundE : Letter

object A: Vowel
object B: SoundE
object C: SoundE
object D: SoundE
object E: Vowel, SoundE
object F: Letter
I can, typesafe, work with subsections of this sealed class; as if they were an enum.
Copy code
fun shouldOnlyWorkWithVowels(example: VowelClassContainingTheField): String {
	return when(example.letter){
		A -> example.aThing()
		E -> example.eThing()
	}
}
in fact, I can do more complicated things like:
Copy code
private fun handle(letter: Letter){
	when(letter){
		A -> "special A case"
		is Vowel -> "the rest of the vowels"
		is SoundE -> "the rest of the ee sounding cases"
		F -> "The final special case"
	}
}
j
For me both are typesafe in the same way, the main different is enums fields are not mutable, meanwhile in sealed you can have data classes But there is no difference in type safety between an enum and a sealed with only objects, and except with inheritance, I would even expect even a linter marking it as something should be an enum
m
Oh I see now, your problem was not type safety, rather a different modeling of your domain. Yes, clearly an enum wouldn't be accurate enough in your Letter example.
y
Keep in mind that you can use sealed interfaces with enums, and so you can have
sealed interface Vowel
j
yeah, I was going to change those object to an enum to report it here as probably it will be the same
m
The core problem was that your letters were an heterogeneous set sharing some traits, while an enum is a homogeneous finite set of elements of the same type, that is sharing the same characteristics.
j
well, E would be a problem and it would be cleaner with objects or even impossible to model them with enum
m
Yes, its exactly the fact that a letter can be multiple things, obviously my example is fake, but my real life usecase covers multiple 'ranges' of values where an enum value can fall under. The beauty about using when with all of this, is how kotlin understand how to make it all exhaustive. obviously they are still enum-like, but you can't model an enum like my example of the letter E. In any case, if PascalCasing becomes the standard, even for enums or constants, I can live with it, even if I don't agree with the readability. I prefer SCREAMING for consts, enums and objects. PascalCasing muddles the water for pattern matching.
e
the convention for
object
is the same as for `class`/`interface`: upper camel case
450 Views