Kotlin - Restrict extension method scope

后端 未结 2 829
暗喜
暗喜 2021-01-06 11:03

Is there a way to restrict extension methods in DSLs?

Say I have a class structure like this:

class Outer {
    fun middle(op: Middle.() -> Unit):         


        
相关标签:
2条回答
  • 2021-01-06 11:25

    The official way to restrict scope is DslMarker. It cannot help in some cases (when you need to annotate java sources, for example) - and here @Deprecated is used. But try DslMarker first.

    @DslMarker
    @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
    annotation class Scope
    
    @Scope
    class Outer {
        fun middle(op: Middle.() -> Unit): Middle { /**/ }
    }
    
    @Scope
    class Middle {
        fun inner(op: Inner.() -> Unit): Inner {/**/ }
    }
    
    class Inner
    

    Thus the last middle call is not compilable anymore.

    0 讨论(0)
  • 2021-01-06 11:45

    You can use a workaround with deprecated:

    class Outer {
        fun middle(op: Middle.() -> Unit): Middle {...}
    
        @Deprecated("can not be used inside a Outer block", level = DeprecationLevel.ERROR)
        fun outer(op: Outer.() -> Unit): Outer = TODO()
    }
    
    class Middle {
        fun inner(op: Inner.() -> Unit): Inner {...}
    
        @Deprecated("can not be used inside a Middle block", level = DeprecationLevel.ERROR)
        fun middle(op: Middle.() -> Unit): Middle = TODO()
    }
    
    class Inner {
        @Deprecated("can not be used inside a Inner block", level = DeprecationLevel.ERROR)
        fun inner(op: Inner.() -> Unit): Inner = TODO()
    }
    

    Now the compiler will give you an error, and IDE will not suggest a wrong function in the completion:

    outer {
        middle {
            inner {
                middle { }  // error
            }
        }
    }
    

    But you really should not do it for big DSLs. It is better to wait for https://youtrack.jetbrains.com/issue/KT-11551 as @KirillRakhman suggested.

    Edit: After I fixed my example, it became much smaller. With one dummy function for a class it is not that much of boilerplate after all.

    0 讨论(0)
提交回复
热议问题