Although I agree with the sentiment, one has to consider:
- in the JVM classes are an obligation
- using functions instead of classes puts stronger requirements on sensible naming of modules and functions. E.g. in python functions from imported modules easily litter your namespace
- not using unneeded classes makes your code harder to read for many colleagues. E.g. if I have a python module universe my colleagues hate it if I import the module and call a function like universe.create() [instead of Universe().create()]
You're always free to use a final class with a private constructor as a namespace for static methods. Many classes in the standard library are of this kind, including `Math`. It's not ideal (see my next point), but it's a far cry from adding extra object instantiations everywhere.
> E.g. in python functions from imported modules easily litter your namespace
I think this is more a problem with the modularity features in a language than free functions themselves. In Python, Haskell, and Agda, I make sure that every symbol I use is explicitly imported (or defined in the same file). This makes it way easier to trace where each symbol I use is defined.
You're basically forced to do this in Java, too, with exception of wildcard static imports, which I very rarely use.
> if I have a python module universe my colleagues hate it if I import the module and call a function like universe.create() [instead of Universe().create()]
They hate it? I can understand if your colleagues aren't developers by trade, but I expect anyone who maintains code for a living to understand the language they're using. There will always be dark corners, but this ain't one.
> You're always free to use a final class with a private constructor as a namespace for static methods. Many classes in the standard library are of this kind, including `Math`. It's not ideal (see my next point), but it's a far cry from adding extra object instantiations everywhere.
And you literally gained nothing. You do exact same thing with slightly different syntax.
A version of Math that had non-static methods instead of static ones would be strictly worse IMO. Extra allocations, extra line noise from instantiations, very likely many users would start keeping Math objects around as local, member, or even static (lol) variables.
In Java, not the JVM. Some JVM languages like Kotlin and Clojure allow for classless functions.
You could argue that it still gets compiled to bytecode with classes, but then that bytecode gets JIT'd to not have classes again anyway so it's kind of a meaningless distinction.
'class' is a first class concept in the JVM. You can't really argue that it isn't by saying it's not in the layer below the JVM or the the fact a layer above it can hide it from you. You can't have a JVM without classes.
I mean, the original post was about programming languages, but The JVM is a virtual machine. It does not have "classes" in the programming sense because it takes bytecode, not source code. A bytecode class isn't the same as a source code class. It would be like saying that x86 has if statements because it has branch instructions.
I interpreted the comment to mean "JVM languages" but if you wanna discuss the JVM itself (which is nonsensical comparison here imo) then yeah sure, it needs "classes".
Well, the JVM is very vocal about having classes as a basic abstraction. Sure, everything is just bits at the end, but the additional abstraction here is Kotlin and Clojure hiding the classes, in my opinion. But sure, it’s not a fruitful topic to argue on :D
> not using unneeded classes makes your code harder to read for many colleagues. E.g. if I have a python module universe my colleagues hate it if I import the module and call a function like universe.create() [instead of Universe().create()]
This sounds like a bit of a weird argument to me. Of course convoluted or strange solutions should be avoided, but `import universe; universe.create()` doesn't sound particularly strange in Python, and it's hard to see how there could be a problem reading it unless it's simply due to being used to a different style. People being used to a particular style could be seen as an argument for that style if that style is indeed a common convention in the language, but if `Universe().create()` is the style they're used to, that sounds more idiosyncratic than idiomatic in Python to me. Do your colleagues perhaps have a background in a different language?
Local conventions at a particular organization may of course also be valuable to follow even if they're not global conventions for the language. But that doesn't really change what is and isn't a good style more generally.
(`from universe import Universe; Universe.create()` would sound like a typical style to me if a class for universes were warranted in the first place, but in that case the class isn't unneeded.)
> not using unneeded classes makes your code harder to read for many colleagues
This would be really depressing for me but ultimately team limitations sometimes win out. If your team can only "understand" code that looks like Java, then maybe all code has to look like Java.
In white collar environments, "don't understand" can be a sneaky, faux-polite way of saying "don't like and refuse to be open to". But it might add up to the same thing in the end.
Fair enough but it does suck that it has to be that way. But yeah, fair enough.
> Classes allow namespacing
This is the same mode of issue as the above: when your language doesn’t support arbitrary namespacing or (hello Python, hello Java) then yes classes can get used as namespaces in disguise. It sucks that it has to be this way in these languages, but we play the hand we’re dealt. Great point
> My colleagues have stylistic preferences
I’m struggling to understand this one. Are you saying that your colleagues prefer instantiating classes over functions, just because, or is there a technical reason for that convention?
> It sucks that it has to be this way in these languages
Not really? I don't see why it matters whether the namspacing keyword is `namespace` or `module` or `class`. If all you want is modularity, they work pretty much the same.
This feels like a bikeshed issue. There's nothing fundamentally wrong with `Math.min()` or just `min()` with a static import.
That would be a case for an enumeration, not a plain class. This usage would make me think: "And where does it get instantiated?" It is a fake class and this usage should be avoided.
I'm not sure what your point about imports in Python means. Normally you shouldn't import *, you just import the functions/classes you need, so nothing pollutes your namespace.
And for your last example did you mean `Universe.create()`? It should be a static or class method. Those are perfectly fine when they're closely related to the class itself, as with factory methods.
- in the JVM classes are an obligation
- using functions instead of classes puts stronger requirements on sensible naming of modules and functions. E.g. in python functions from imported modules easily litter your namespace
- not using unneeded classes makes your code harder to read for many colleagues. E.g. if I have a python module universe my colleagues hate it if I import the module and call a function like universe.create() [instead of Universe().create()]