Infix with additional lambda

I totally get it when it is not implemented, as it can cause confusion, but…

I would like it a lot if it’s possible to ad an extensionFunction like this:

class Clazz
class Interface
class Body
infix fun Clazz.extends(interf: Interface, lamb: Body.()->Unit)

myClazz extends myInterface{
     //classBody
 }

I think that the infix-function would most of the time be used in a DSL.
This means that the lambda is most of the time an extension-function of a special DSL-class.
This means that if a special method inside the lambda would be called, the lambda only compiles if it uses the special DSL-class.
Therefor, the precedense can still use the member-properties of the class first:

class Clazz{
     opertator fun invoke(lamb: ()->Unit) = Unit
}

class Interface
class Body{
    fun varProp(name:String) =  Unit
}
infix fun Clazz.extends(interf: Interface, Body.()->Unit)
infix fun Clazz.extends(interf: Interface)

myClazz extends myInterface{
     //can invoke both -> member-functions go first
 }
myClazz extends myInterface{
    varProp("") // can only invoke Body -> body
}

Another option would be that it isn’t allowed to add both extends at the same time.

Although the last example would probably not occur very often, as most of the cases, the DSL inclusive Data-classes belonging to the DSL would be under your own controll.

2 Likes
class Clazz
class Interface
class Implementation
class ImplementedInterface
    
operator fun Interface.invoke(implement: Implementation.() -> Unit): ImplementedInterface
infix fun Clazz.extends(implementation: ImplementedInterface)
    
val myClazz = Clazz()
val myInterface = Interface()

myClazz extends myInterface {
    //implementation
}
1 Like

I know.
The problem arises when you get a lot of classes like this.
Then it becomes a big mess.
(See KotlinPoetDSL).

I want to give acces to as less API-functions as possible, when they cannot be used.
Adding it to the class means therefor that it is way to broad.
This can be limited somehow, by adding it to an interface.
This means that in order to start using the functions of the API you first need to implement an interface.
(I personnaly don’t like this, as calling the function itself tells enough)
This interface brings the invoke-function one level to high: throughout the whole level where you may invoke the function.
With the addition of this function, the invoke-method is added exactly where you need it and nowhere else.

When you have some classes which can be invoked straight away and some classes that don’t, you leave a trap open for the developer, as there is no compiler-warning, which means that API is far less safe.

When this feature will be added, the invoke would become accesible at only the place where it is needed and it will be safe.

I think it could be like this:

class Clazz {
    infix fun extends(clazz: Clazz): Clazz = TODO()
    infix fun implements(iface: Interface): Clazz = TODO()
    infix fun body(block: Body.() -> Unit) { TODO() }
}
class Interface
class Body {
    fun variable(name: String) { TODO() }
}
fun main(args: Array<String>) {
    val superClazz = Clazz()
    val myClazz = Clazz()
    val myInterface1 = Interface()
    val myInterface2 = Interface()
    myClazz extends superClazz implements myInterface1 implements myInterface2 body {
        variable("aa")
    }
}

Although it’s a little more verbose, but cleaner.
Also, you can replace body() method with some operator, for example +=

I undersstand what you mean.
It is cleaner behind the scenes, but I want the API-interface to be as clean as possible, even if it means that my own code would become a bit more ugly.
The only reason why it is cleaner, btw, is because the suggestion in this topic is not introduced.
When it is, this is cleaner and you get a less verbose API.

You get a cleaner, harder to reason about API. What if Interface also had an invoke() method? That makes it harder to determine which to use. Other posts have brought up trying to extend infix functions to use more parameters, but that can always lead to ambiguous situations that either require careful order of operations (and you to learn it) and/or you to surround with parens anyway.
I understand that you’re only asking for lambda, but that doesn’t exactly change anything I said.

At the moment, you can have an extension-function on the object, as well as with specific lasnaad as extension-function.
The infix-function tells which function you need due to the returntype.
I think that will bring more confusion than adding it both the invocation and the infix-function to one function, instead of keeping it separated