I have a class `Processor` that processes some dat...
# getting-started
y
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
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
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
it’s a class because it has shared state
per-instance
c
Shared with whom? From what you've shown us the instance is local to the
process
function call.
y
Processor
has properties, does some (recursive) calculations, and ends up with a solution
j
If
Processor
has state, the
object
option is not viable indeed
y
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
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
yeah. I would have preferred the top-level function, but then I lose the namespacing, right?
👌 1
c
Also, you could just make it regular class.
Copy code
class Processor {
  …

  fun process(): Int
}
1
y
it’s just “process()“, and would need a more descriptive name.
c
What do you mean by namespacing? There is no namespacing in Kotlin.
y
exactly. I’m trying to emulate namespacing here.
apologies if this is an XY problem
c
But you asked what's idiomatic in Kotlin, namespacing is not a thing in Kotlin
j
@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
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
@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
If it's single-use, it should only be internal to a top-level function, indeed
j
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
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
good point! the name itself is now an implementation detail
j
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
@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
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
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
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
@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
Yeah it's an option too, but I find that it usually doesn't bring much apart from an extra indent level
y
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
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
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
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 👍