https://kotlinlang.org logo
#getting-started
Title
# getting-started
y

y

01/19/2023, 10:59 AM
I have a class
Processor
that processes some data and I have a function
process()
that instantiates the class and returns the result. I don’t want to have intermediate state, so I want to disallow creation of this class outside of the file it is declared in. however, I do want to call the function as
Processor.process()
. currently I have
Copy code
class Processor private constructor(...) {
  //...
  private fun finalResults(): Int

  companion object {
    fun process(...): Int {
      return Processor(...).finalResults()
    }
  }
}
is there another way to do this? EDIT: basically, I'm asking for a way to emulate namespaces here.
c

CLOVIS

01/19/2023, 1:04 PM
Looks good to me.
1
If the class is not part of the API at all, why not just
Copy code
fun process(…): Int { … }

private class Processor { … }
Sounds to me like the class shouldn't exist at all, it should probably just be private top level functions
p

psh

01/19/2023, 1:50 PM
If you are trying to group a bunch of processor methods, I would also suggest just making them top level methods. Another alternative might be to use a Kotlin singleton if you really feel you need to wrap them in an object
Copy code
object Processor {
    fun processOne (): Int {
        return 123
    }
    
    fun processTwo (): Int {
        return 456
    }
}
y

y

01/19/2023, 1:58 PM
it’s a class because it has shared state
per-instance
c

CLOVIS

01/19/2023, 1:59 PM
Shared with whom? From what you've shown us the instance is local to the
process
function call.
y

y

01/19/2023, 2:01 PM
Processor
has properties, does some (recursive) calculations, and ends up with a solution
j

Joffrey

01/19/2023, 2:01 PM
If
Processor
has state, the
object
option is not viable indeed
y

y

01/19/2023, 2:02 PM
an example of this would be a
BufferedReader
that is initialized with a file path, and the result is a String of the file
j

Joffrey

01/19/2023, 2:02 PM
But the top-level function + private class is a good alternative if you don't like your current approach. That said, I find the
Processor.process()
call site nice with the current approach
y

y

01/19/2023, 2:03 PM
yeah. I would have preferred the top-level function, but then I lose the namespacing, right?
👌 1
c

CLOVIS

01/19/2023, 2:03 PM
Also, you could just make it regular class.
Copy code
class Processor {
  …

  fun process(): Int
}
1
y

y

01/19/2023, 2:03 PM
it’s just “process()“, and would need a more descriptive name.
c

CLOVIS

01/19/2023, 2:04 PM
What do you mean by namespacing? There is no namespacing in Kotlin.
y

y

01/19/2023, 2:04 PM
exactly. I’m trying to emulate namespacing here.
apologies if this is an XY problem
c

CLOVIS

01/19/2023, 2:05 PM
But you asked what's idiomatic in Kotlin, namespacing is not a thing in Kotlin
j

Joffrey

01/19/2023, 2:05 PM
@CLOVIS The regular class may or may not be viable here. It gives more control to the user and they are then allowed to call multiple times the public functions of the class on the same instance, which may break depending on what the state is
c

CLOVIS

01/19/2023, 2:06 PM
I'm not sure why you want the
process
top-level function, but it seems to me like you could just make a regular class that accepts
process
' arguments as constructor parameters.
y

y

01/19/2023, 2:07 PM
@Joffrey explained it very well. I don’t want to allow reuse of the class instance (which may lead to illegal state) and also I don’t want to expose implementation details of the
Processor
class.
I’m starting to think the top-level function approach is the most idiomatic.
c

CLOVIS

01/19/2023, 2:08 PM
If it's single-use, it should only be internal to a top-level function, indeed
j

Joffrey

01/19/2023, 2:08 PM
I would go with either a top level function with a private class to hold temporary state, or your current approach. Both are pretty good answers to your problem
👍 1
The difference is in the call site
Some people have strong opinions against top-level functions
c

CLOVIS

01/19/2023, 2:09 PM
I prefer the top-level function + private class because the class is not part of the API at all, so you can just remove it in the future
If you keep your current version, you are stuck with that class name and API (in your case: everything must always be private)
y

y

01/19/2023, 2:09 PM
good point! the name itself is now an implementation detail
j

Joffrey

01/19/2023, 2:09 PM
If the class has no public methods except the companion object, then it serves as a namespace, which might be desirable in big projects to avoid bloating the auto completion of the top level scope
c

CLOVIS

01/19/2023, 2:11 PM
@Joffrey no, the companion object serves as namespace. The class is useless in the API and stops you from changing it in the future. If you just want "a top-level function that isn't by default in code completion", you want a regular object.
j

Joffrey

01/19/2023, 2:11 PM
Actually there is a third option: private class for the internal state, and then an
object
next to it, with its own name to hold the public functions you want to support
👍 1
Haha yes I was writing exactly that actually
c

CLOVIS

01/19/2023, 2:12 PM
Actually if you are going with an object for the API, I would nest the private class in the object, but that's just personal preference since it's not part of the API anyway
y

y

01/19/2023, 2:13 PM
so you can “namespace” with the public class’s companion object, and the Processor itself is a private-in-file class with a regular constructor.
that seems like a better api.
c

CLOVIS

01/19/2023, 2:13 PM
@y what @Joffrey meant:
Copy code
object Processor {
    fun process(): Int { … }
}

private class YourInternalState(…)
1
Personally I'd put the private class in the object, but I don't think there's any standard decision on this
j

Joffrey

01/19/2023, 2:15 PM
Yeah it's an option too, but I find that it usually doesn't bring much apart from an extra indent level
y

y

01/19/2023, 2:15 PM
oh, right. so there’s not even a need for a companion.
👍 1
definitely prefer this approach. I’m glad I started this discussion.
j

Joffrey

01/19/2023, 2:16 PM
Also it gives you the opportunity to give 2 different names. Because the namespace for the stateless top-level operations might not be a suitable name for the state holder
c

CLOVIS

01/19/2023, 2:16 PM
The good thing with this is that your internal class is 100% an implementation detail, even its existence is invisible. You also don't need to put
private
on everything, since the entire class is private
y

y

01/19/2023, 2:16 PM
exactly. maybe in the future you want to break the private Processor class into several classes or whatever.
👍 2
thanks a lot both of you 👍
4 Views