Before I open a feature request or make a compiler...
# language-proposals
p
Before I open a feature request or make a compiler plugin, I thought I ask... Is there a way to restrict DSL calls? For instance, to allow calling a certain function only once (or X amount) as well as maybe restricting the order they are called...
p
I’m not sure if this is possible with DSLs, and it will probably be ugly to write (but OK to consume)
Copy code
interface ApiStep1 {
   fun configureA(value: String): ApiStep2
}

interface ApiStep2 {
   fun configureB(value: String): ApiStep3
}
interface ApiStep3 {
   // ... all other things you'd like to expose in the DSL
}
Consuming it (not in a DSL):
Copy code
someBuilder() 
   .configureA("Hello")
   .configureB("World")
   .yadaYada()
   .build()
d
I think you could pull this off for DSLs, if you have the methods cast the receiver by contract.
p
@pedro Yeah, I’m aware of creating restrictions like that for chaining builders 🙂 That however forces the consumer to call that function, but in some cases could have an optional function call that should only be called once if any. This could be useful for something like:
Copy code
callbackFlow {
  // do something
  onCancel {
    
  }
  // if anything is called after onCancel then we throw a compiler error
  onCancel {
    // this block would give a compilation error 
  }
}
@Dominaezzz I was wondering if there is anything on the contract API that could do that 🤔
d
Not sure. It's all in theory.
p
Yeah, I thought you’d know about that pattern but maybe you were blocked 😛 the particular example you wrote could be achieved by
Copy code
callbackFlow {
 // do something
} onCancel {
}
where
onCancel
is just an infix function. Although you probably don’t want to change the callbackFlow API but this could work if that was just an example. On the other hand, this syntax is a bit weird and is a lot more limited than what you asked originally… Hoping maybe we can iterate it further 😬
p
Appreciate the help 🙂 I’m more wondering about a general purpose solution for Kotlin to make dsl implementations more “safe”. Other use case could be, in Compose for example, where, if we add padding twice, the last one is applied but not the first one. Basically a way to disambiguate DSLs 🙂
👍 1
r
you can use RestrictSuspension and suspend functions only for that purpose
they can restrict foreign suspended functions are not accepted unless defined over the Restricted Scope.
unless they are inline which is a pass through on both pure and suspended coded
d
We are working on special contracts with which you can declare exact number of invocations of some functions/setters inside your DSL So it's no need to open request for this
😍 4
But I can't tell you any estimate when such contracts will be added to language
p
Nice! Thank you @dmitriy.novozhilov 🙂 That will be a great addition to contracts 💯 Will the final version include order too? Or at least if it’s called before or after the rest of the body of the block. It would probably make it much more complicated though 🤔
d
We didn't think about it, but will consider. Looks like it'a not hard to implement, but we need to provide smooth design for all contacts system
💯 2
e
@pablisco Please, post your actaul use-cases.
p
@elizarov I have an API that allows to create a stream of items and there is an api call that signals the end of the stream. I would like to make sure the compiler complains if the user sends any more items after the end signal is sent. Hence avoiding sending new items after the stream has been terminated.
n
@elizarov I also would use something like this for a networking library, it's stream based and uses a close stream signal