Andrey Solera
Andrey Solera

Reputation: 2402

Kotlin named constructors

I have the following code in Dart programming language

class HttpResponse {
  final int code;
  final String? error;

  HttpResponse.ok() : code = 200; <== This functionality 
  HttpResponse.notFound()         <== This functionality
      : code = 404,
        error = 'Not found';

  String toString() {
    if (code == 200) return 'OK';
    return 'ERROR $code ${error.toUpperCase()}';
  }
}

How can I achieve this in Kotlin, I know that I can use static methods, however static methods don't have the purpose of initializing a class, is there a way where this can be achieved in Kotlin?

Upvotes: 6

Views: 4018

Answers (3)

PesaThe
PesaThe

Reputation: 7499

I agree that sealed class is the preferred way but there is another option of making the constructor private and accessing it via factory methods in companion object. That way you can achieve "named constructors".

data class HttpResponse private constructor(
    private val code: Int,
    private val error: String? = null,
) {
    companion object {
        fun ok() = HttpResponse(200)
        fun notFound() = HttpResponse(404, "Not found")
    }
}

fun main() {
    val responseOk = HttpResponse.ok()
    val responseNotFound = HttpResponse.notFound()
}

Upvotes: 3

Nick
Nick

Reputation: 61

Sealed Classes is the way to go:

import java.util.Locale.US

sealed class HttpResponse(val code: Int, val error: String?) {
  object Ok : HttpResponse(200, null)
  object NotFound : HttpResponse(404, "Not found")

  override fun toString() = when (this) {
    Ok -> "OK"
    NotFound -> "ERROR $code ${error?.uppercase(US)}"
  }
}

fun main() {
  println(HttpResponse.Ok) // OK
  println(HttpResponse.NotFound) // ERROR 404 NOT FOUND
}

Since I cannot suggest an edit or post a comment, I am adding my modified version of zOqvxf's answer here.

If you keep your superclass parameters unexposed in this way, there is no worry for usage like HttpResponse.Ok(404) as mentioned in the comment.

Upvotes: 2

zOqvxf
zOqvxf

Reputation: 1579

You're looking for Sealed Classes.

sealed class HttpResponse(val code: Int, val error: String? = null) {
    
    class Ok(code: Int) : HttpResponse(code)
    
    class NotFound(code: Int, error: String?) : HttpResponse(code, error)
    
    override fun toString(): String {
        return if (code == 200) "OK"
        else "ERROR $code ${error?.toUpperCase()}"
    }
}

fun main() {
    val okResponse = HttpResponse.Ok(200)
    val notFoundResponse = HttpResponse.NotFound(404, "Not found")
}

Upvotes: 9

Related Questions