Creating your own 'for .. in' type loops?


#1

In Kotlin you can use 'for ... in' with any type that has can provide an 'iterator' method ... either directly or via extension.

The question is can you express a similar thing in your own methods, i.e. parameterized on this type … providing it has the given method (directly or via extension)?

Now what I’d like to say is something like (for example):

abstract class Pretty class PrettyString(val str: String): Pretty() class PrettyList(val items: List<Pretty>): Pretty()

fun String.pretty(): Pretty = PrettyString(this)
fun Int.pretty(): Pretty = PrettyString(this.toString())

fun <T /* where T has a .pretty method */> List<T>.pretty(): Pretty =
  PrettyList(this.map { it.pretty() })


val stuff: Pretty = listOf(“Hello”, “this”, “is”, “pretty!”).pretty()

In Scala you’d define a ‘Prettyfiable’ trait and then define a bunch of implicit conversions from String, and Int and List into Prettyfiables. You could then define how to Pretty a list, providing you can pretty the type of the list. In Haskell you would use type classes to do a similar thing.

A solution using extension methods would be far less scary than the Scala solution … but I have no idea whether Kotlin can support this …


#2

About the only two ways of doing this are structural types (kind of what your high-level description proposes) and implicit consverions (what Scala does). The first is too costly performance-wise. The second imposes a lot of subtle problems, as any implicit mechanism. Kotlin's approach is to avoid implicits. You can still explicitly wrap your data and make use of Kotlin's delegation facilities.


#3

Maybe this will do what you want

``

fun <T>T.pretty(): Pretty = when (this) {
  is String -> PrettyString(this)
  is Int -> PrettyString(this.toString())
  is Any -> PrettyString(this.toString())
  else -> throw UnsupportedOperationException()
}

fun <T> List<T>.pretty(): Pretty = PrettyList(this.map { it.pretty() })


#4

What about:

public fun Pretty Object.pretty() {   return PrettyString(this.toString()) }

public fun Pretty Int.pretty() {
  return PrettyInt(this)
}

public fun Pretty Float.pretty() {
  return PrettyFloat(this)
}

public fun Collection<T>.pretty(): Pretty = PrettyList(this.map { it.pretty() })


Pattern matching is mostly a suitable fit when parsing data. All the Scala samples I have seen are about parsing data or code. Also, there is a reply by Martin Odersky to some blog post where the author is in doubt about the genericity of pattern matching compared to the respective OO solution. I googled a bit for it, but couldn’t find it in reasonable time. The reply by Odersky is that pattern matching is mostly a better solution compared to the OO solution when parsing data (avoiding the visitor pattern, e.g. a smaller hammer appropriate for the size of the nail). An example he makes is generics in Java as he implemented them (and that again is about parsing code compared to general use).

– Oliver


#5

Ah that's interesting because I'm wondering how you're implementing, for example this code:

import java.util.ArrayList

trait Factory<T> {
  fun create(): T
}

data class Foo {
  class object : Factory<Foo> {
  override fun create() = Foo()
  }
}

fun <T> bar(items: ArrayList<T>) where class object T : Factory<T> {
  items.add(T.create())
}

fun main(args: Array<String>) {
  var items: ArrayList<Foo> = arrayListOf()
  bar(items)
  println(items[0])
}

This compiles fine but currently doesn’t execute due to some bugs.

However given the type-erasure the only way I can see this working is by passing an implicit extra argument for the class object … i.e. effectively automatically transforming it to …

fun <T> bar(factory : Factory<T>, items: ArrayList<T>) {   items.add(factory.create()) }

fun main(args: Array<String>) {
  var items: ArrayList<Foo> = arrayListOf()
  bar(Foo, items)
  println(items[0])
}

Now you can do the same trick for my example … I’m not saying you should, more features is not always better … simply that it I believe it could be implemented efficiently without implicit objects …

That is, you could automatically transform this

fun <T /* where T has a .pretty method */> List<T>.pretty(): Pretty =   PrettyList(this.map { it.pretty() })

fun main(args: Array<String>) {
  val stuff: Pretty = listOf(“Hello”, “this”, “is”, “pretty!”).pretty()
  println(stuff)
}

into this

fun <T> List<T>.pretty(dict: (T) -> Pretty): Pretty =   PrettyList(this.map { dict(it) })

fun main(args: Array<String>) {
  val stringDict = { (x: String) -> x.pretty() }
  val stuff: Pretty = listOf(“Hello”, “this”, “is”, “pretty!”).pretty(stringDict)
  println(stuff)
}

each concrete class that used the functionality would need to have its own dictionary … which is kind of manageable.


#6

Yes you can achieve a similar effect by using pattern matching, but like Oliver says sometimes polymorphism is best achieved through pattern matching, but sometimes it's best achieved through OO style.

In particular pattern matching is good when you know the set of things you want to be polymorphic over is limited, but the operations you want to perform on them is not. Pattern matching polymorphism makes it hard to add new types to be polymorphic over, but easy to add new polymorphic operations.

In contrast OO style polymorphism is the other way round. It’s good when you know that the set of operations is limited, but the types you want to perform the operations on is not limited. OO style polymorphism makes it hard to add new operations, but easy to add new types.

The real power comes when you can freely choose whichever type of polymorphism fits your problem best. The problem I describe above fits the OO style much better, the only operations I’m doing is pretty printing … but I can think of all sorts of types that I might want to pretty print.

I think that being able to use extensions methods polymorphically would greatly extend the power of Kotlin. The ability to use ‘any class with an iterator method’ in for loops is very tantalizing and indicates how useful the feature could be. It essentially allows you to say “I can make class X implement interface Y even if I can’t modify class X”. Since all you need to do is define an extension method that returns that interface. You get much of the power of Scala’s implicit conversions, but avoiding almost all of the pitfalls.

I can think of several efficient implementation strategies:

Implementation strategy 1. Dictionaries

The first (as I described above) is to use dictionaries passed as an implicit argument, this is how Haskell does it. As I said above, if Kotlin is going to support the use of class objects in the ways that the compiler currently allows then it’s going to need to do something like that anyway.

Implementation strategy 2. inline

The second implementation strategy is simply to say that you can use structural typing, but the methods in question must be declared inline. Thus my example would need to be:

inline fun <T> List<T>.pretty(): Pretty where T.pretty(): Pretty =   PrettyList(this.map { it.pretty() })

When someone calls the method the compiler inlines the correct .pretty() call for whatever concrete type is used. This is essentially how the ‘for … in’ construct works, the compiler inlines the for-in and inserts the correct .iterator() call at the call site. The constraint that the function must be inline is not a big constraint in practice, and the performance overhead for the feature is essentially zero.

Dictionaries are a bit more powerful: it’s easy to see how to implement

``

class Foo<T> where T.pretty(): Pretty

when using dictionaries … much harder for inline. But inline is likely to be more efficient.