Hacker News new | ask | show | jobs
by ptx 3306 days ago
The "Fully Fluent API" seems to be a style adopted as a workaround for the clumsiness of the Java language, as far as I can tell. In Kotlin it's not necessary and just looks a bit weird.

This example in Java:

  Javalin app = Javalin.create()
      .port(7000)

  app.start()
     .awaitInitialization()
     .stop()
     .awaitTermination();
could be written more naturally in Kotlin:

  val app = Javalin.create().apply {
      port = 7000
  }
  
  with(app) {
      start()
      awaitInitialization()
      stop()
      awaitTermination()
  }
...except that Javalin doesn't seem to implement the normal convention for getters and setters, so the apply block wouldn't work.
3 comments

Thanks, this is good feedback. I'm still at the stage where I'm "writing Java in Kotlin".
Are you really saving much? Non-fluent API:

    Javalin app = Javalin.create()
    app.port(7000)

    app.start()
    app.awaitInitialization()
    app.stop()
    app.awaitTermination()
And three lines shorter than the kotlin one.
In this case we happened to have a variable already defined with a short name, but in other cases the name might be longer or you might have to introduce a temporary variable. If you don't need the reference to app in the rest of the program, you can do away with the name entirely:

  with(Javalin.create()) {
      port = 7000
      start()
      awaitInitialization()
      stop()
      awaitTermination()
  }
When in comes to the question of how much this is saving us... the Java designers seem to have thought it was worth something, since Java has a somewhat similar feature: a method calling another method on the same object can leave out "this".

Python on the other hand doesn't have the implicit "this", so the JUnit API (the unittest module in Python) actually becomes uglier in Python. Instead of this in Java:

  class TestNumbers extends TestCase {
      public void testArithmetic() {
          assertTrue(1 + 1, 2)
          assertFalse(10 * 10, 100)
      }
  }
Python needs an explicit self variable:

  class TestNumbers(unittest.TestCase):
      def test_arithmetic(self):
          self.assertEqual(1 + 1, 2)
          self.assertEqual(10 * 10, 100)
> the Java designers seem to have thought it was worth something, since Java has a somewhat similar feature: a method calling another method on the same object can leave out "this".

True, though the reason what that Java should be "familiar", so it did the same thing as C++.

IMO, Python did the right thing by not having magic variables.

Functional code + this starts getting messy, ala JS.

Is "with" a keyword, or is it just convention - I haven't been able to find it documented anywhere. It seems like it's just doing a function with receiver under the hood.
Thank you - searching for the word with was unfruitful for me.
This is a recurring theme with Kotlin: inline receiver functions with a lambda parameter are an amazingly versatile tool for building functions that implement what would be a language feature/syntactic sugar in other languages. `with` here is a good example, but `let` and `use` are other good examples of this in play (`use` gives you try-with-resource, let plays nicely with the ?. safe navigation operator to execute code on non-null objects `maybeNullObject?.let { doStuffWith(it) }`)