While developing library in DSL style some thought...
# language-proposals
p
While developing library in DSL style some thoughts came: what if there was possibility to constraint methods with how much they can be invoked and with constraints on reference copying. It can help finding mistakes of library usage at compile time. For example, consider builder pattern:
Copy code
// interfaces declaration

@NotReferencable
interface SomeBuilder {
   
   @AtLeastOnce
   fun author(name: String)

   fun comment(text: String)

   @ExactlyOnce
   fun body(lambda: SomeScope.()->Unit)
}

fun build(lambda: SomeBuilder.()->Unit)   


// usage

var builder: SomeBuilder? = null

build {
   
   builder = this // ERROR cause SomeBuilder is constrained with @NotReferencable 	
  	

   author(name = "Test name 1") // OK (if comment this line and line after than it is error at compile time, cause fun author must be called at least once)
   author(name = "Test name 2") // OK

   comment(text = "Comment 1") // OK (if comment this line and line after it still will be OK, cause there are no constraints for this function)
   comment(text = "Comment 2") // OK
   
   body {} // OK
   body {} // ERROR cause exactly once constraint specified, if comment both lines that it will be an error cause of the same reason 
}
👍 2
👍🏻 1
y
ExactlyOnce and AtLeastOnce can be done with a parameter, and a parameter + variable. Also, the value class design notes talks about adding something akin to AtLeastOnce and talks here about adding something akin to ExactlyOnce. I think because of compiler magic it would eliminate the need for NotReferencable.
m
That's definitely a neat feature. There are some ideas of extending our contracts to cover similar cases, plus having more control over aliasing, aka immutability. But could you share more details about your domain and the specifics of your DSL?
p
My use case is very similar to patterns (there are a lot there, just few for example): - Ktor (io.ktor.client.request.HttpRequestBuilder) (only runtime check for url specified) - Kotlin compiler org.jetbrains.kotlin.ir.builders.declarations.IrFunctionBuilder (only runtime check for name specified)
Also, there can be one more enhancement to original proposal: constraint that check at compile time that only one of several methods in some declared group was invoked. For example:
Copy code
// interfaces declaration

interface SomeBuilder {

  @ExactlyOnce(group="bodyGroup")	
  fun body(lambda: SomeScope.()->Unit)
  
  @ExactlyOnce(group="bodyGroup")
  fun body(script: String)

} 


fun build(lambda: SomeBuilder.()->Unit) 


// usage

build {

  body {} // OK
  
  body("some script") // ERROR cause function with constraint @ExactlyOnce and same group=bodyGroup was already invoked

}
h
I also do have the same use-case, to prevent reconfiguration, but I think (!) it should be possible to do this with a compiler plugin today, shouldn't it?
1
p
Yes. I was thinking of it. But this case is used in many places that makes me think that it better to include it in compiler. So that for example the compiler itself can use this feature for own builders.