What is the advantage of "companion object" vs static keyword

Most of the time a static method can be replaced with an extension method or a ‘package’ method. Your example of
WorkerBee.checkValidity(value)

I can just write

checkValidity(value)

could become value.checkValidity().

Depends on types.

I suspect the designers are trying to have us approach problems from a different perspective perhaps.

P.S.
And have you looked at Microsoft recently, and what they’re doing? Time to drop the antagonistic M$. IMO it weakens your statements.

2 Likes

Au contraire. Yes, Microsoft is doing a nice job of integrating UNIX/LINUX into Windows 10, something Steve Jobs did 15+ years ago. However, every other move that MS has made under Nadella is right out of the “embrace, extend, extinguish” playbook that has been the central philosophy of Microsoft from day 1. e.g. Xamarin - what did they do almost immediately after purchase? Terminate support for Java. Do not be naive - Microsoft has not changed its stripes.

1 Like

Let’s put the MS discussion aside. I should not have brought it up.

I’m curious. Did the Kotlin portion of my comment help at all?

I think Kotlin is trying to provide alternatives to class methods for a number of situations. Keep the ‘class’ focused on instance methods/properties ONLY, and not mix class methods/properties with instance methods/properties.

Utility functions can often become extension functions, or get defined at the top (package) level. i.e. completely outside the class definition. Constants should be defined outside the class, and not in a companion object.

The object outside a class is for Singletons, and the companion object is a bit fuzzier. Factory/builder methods fit nicely into a companion.

At least that’s my interpretation/understanding/usage pattern right now.

For your setDefaultPermissions example, I would envision an extension function for the various types, and since the function is tied to a type, you can use the same name. And it can be more performant as the compiler will often inline extension functions.

4 Likes

My attitude about statics is very simple. If it’s not broke, don’t fix it. Unfortunately…

Statics in Java are easy to code (there is no outside, inside or other container), are easy to understand even for novices (who generally are tasked with maintenance), and, most importantly, fit very nicely into the wonderfully robust package/namespace design paradigm that Java pretty much invented and is the basis for Kotlin. Yet for some reason, the Kotlin designers decided a static should be singleton - which it is not. Kotlin is not a functional programming language, and everything is not an object (e.g. package level functions). Any attempts to make it such are doomed to create more complexity and to fail the obviousness test (ie. I shouldn’t need to read a manual to guess correctly what this unfamiliar thingy does).

Yes, your recipe for how it can be made to work, sort of, along with the suggestions of others in this thread is interesting. However, your reply is not responsive to my question. So I’ll restate it here -

What is the advantage of Kotlin’s design vs. Java statics?

1 Like

I am sorry, but this is total nonsense. Nobody picks up a programming language or technique without study. Try reading functional (e.g. inject, a.k.a. fold, reduce, accumulate, aggregate and compress) or reactive code (e.g. amb) if you come from a different background.

Just because you are now so familiar with statics that they feel natural, does not mean that they are. If you had extensively used other languages that do not have statics, you would probably think that statics are totally useless.

Companions are objects. That means you can pass them around just like all the other objects in Kotlin. Combined with the fact that they can implement interfaces, you have the capability to have 1 interface for, for example, factory methods for multiple types. And you have the flexibility to mix companion objects with “normal” class instances that also implement that interface.

3 Likes

AFAIK, every other mainstream language in use today has statics that are simple to use and grok - C, C++, C#, Javascript, Python, Swift, and, of course, Java come to mind. Kotlin needs to get on board with this feature or it might be one of the reasons Kotlin fails to gather enough use to succeed.

In my experience, statics are often an anti-pattern that is to be avoided.

I see a lot of advantages of Kotlin (companion) objects over statics and statics can be emulated with annotations.

1 Like

That is a strange position: You want to design a better language, but it must include constructs that are popular in a lot of other languages.

Seriously? That’s your suggestion? Use annotations?

Well then why didn’t you throw out suffix ++ and - - while you were at it? I’m told they are to be shunned because they have a side effect. I’m sure that would make your comrades in your ivory tower pleased.

Kotlin is not about an ivory tower. It is a very pragmatic language. It just achieves this pragmatism in other ways than the currently popular languages do. These ways were decided upon after lengthy deliberation.

Because different constructs were chosen for Kotlin in some cases, you have to adjust the way you design your solution. I, for example, love non-nullable types, so I now write code in Kotlin differently than the way I did in Java, so I (almost) always only deal with non-nullable types. ?. and !! are code smells to me, so I try to avoid them whenever I can.

If you don’t like Kotlin in some respects, there are many, many other languages that run on the JVM (and some also compile to JavaScript) that you can try.

1 Like

I’m saying that using statics is often a bad code-smell, an anti-pattern, in a number of ways. Inability to have overloading, or problems mocking static methods for unit testing - have all bitten the code I’ve been working on in the past.
Those are real-life pragmatic issues.

But if you must have something that the JVM sees as a static, for reasons of interoperability, then add annotations where you must.

And otherwise, I fail to see a big deal in it. I really can’t.

Others have already tried answering the question in the subject of the thread: what advantages are there?

But it seems you persist in only being able to see disadvantages, and insist on adding a particular feature to the language only because it suites you, and because “other languages have it too!”. Which is not a very strong argument - just because all the other lemmings walked over the edge, should I do it too?

1 Like

One small note: Java did not invent packages. They were invented by Pascal related languages, first Modula as modules and then Ada as packages. Ada still lives as in Oracle PL/SQL (Ada subset), and packages are kicking there all right.

To me Java was a new language with best features taken from:

  • Pascal: JVM. Many Pascal implementations ran on bytecode
  • Ada: packages
  • C++: syntax variants with classes

Ada was “Object based”, while C++ “Object oriented” and here we are.

What? In Java you don’t have to write,
WorkerBee.checkValidity(value)

Unless you are outside the scope of WorkerBee.

How to mock companion object and how to overload methods in companion object of a super class companion object?
Can you please show some examples?

Create an interface for the object, and use dependency injection instead of referring to the companion directly. In the tests you can inject a mock.

I like the concept of companion object. A companion object is a true object that has all the behaviour of an object. You can define a companion object which extends abstract class or implements interfaces. You can also pass a companion object as argument to a function. Companion object is truly OO; whereas Java static is not. One thing I would like the Kotlin team to add to the language is a more convenient way to define companion object methods without the tediousness to write a complete class structure. For example,

class MyClass {

    companion fun foo() {
    }

    companion fun bar() {
    }
}

is equivalent to

class MyClass {

    companion object {

        fun foo() {
        }

        fun bar() {
        }
    }
}

Any functions declared with the “companion” keyword will be automatically added to the companion object. If the companion object is not explicitly defined, it will be defined implicitly whenever there is a companion function defined in the class.

5 Likes

In this case there is no sens to make static members, we make a simply class and inject this class

In most cases it does not make sense to use static members because they are global variables, and using global variables leads to inflexible and fragile code. If you have behavior that you want to be able to change (even if it is just for testing), you should switch to dependency injection (of a type or a function).

So, why in this case we even need object if dependency injection library will take care of that class should be singleton?

In general, if there are no member properties, then you can use an object instead of a class, which make it clear there is no point in creating multiple instances.

You would use a companion object if you do not want to expose certain constructors, fields or properties of a class. These members can have private access. The companion object can access them, allowing you to control how these members are used.