so im making some bad decisions to create a DSL: ...
# random
so im making some bad decisions to create a DSL: what I wanted was basically intelliJ to give me a kind of folder-path style autocomplete, where i could write something like
Copy code
val domainRelevantKey = Root / HighDomainTerm / MediumDomainTerm / LowDomtainTerm("runtime value!") / OptionallyAFeature
which would be a kind of key for use in our application. As you can imagine by its pathy-ness this kind've imposes a hierarchy on my app, which is what im looking for. I did get this... with a boatload of pretty strange code: Some pros: - use of static symbols like this means spelling mistakes become compiler errors (where if I'd used some more dynamic things involving strings, I'd likely see misbehaviors that given my usage would be difficult to find in tests) - its likely going to be pretty readable; anybody reading
val relevantSection = Root / Model / ...
is going to understand its usage. - its reasonably extensible in as far as java-with-boilerplate is extensible, in that you can copy-paste-change and have it likely work for your purposes. some cons: - nobody will ever understand my inheritance scheme, I'm pretty sure I wont in 3 months. - each new symbol/domain concept requires more code. A purely dynamic solution wouldn't have this problem --except of course at callsites. - seems pretty overbuilt
to expand on my statement, this works now with
import Level1.*
import Level2.*
, etc. but if we had context-sensitive resolution, the compiler could pick those up without additional namespace pollution
Copy code
interface PathSegment<Child>
sealed interface Path<Last : PathSegment<*>> {
    val segments: List<PathSegment<*>>
data class Nested<Last : PathSegment<*>>(val parent: Path<*>, val child: Last) : Path<Last> {
    override val segments: List<PathSegment<*>>
        get() = parent.segments + child
object Root : Path<Root>, PathSegment<Level1> {
    override val segments: List<Nothing>
        get() = emptyList()
enum class Level1 : PathSegment<Level2> {
    HighDomainTerm, // ...
enum class Level2 : PathSegment<Level3> {
    MediumDomainTerm, // ...
sealed class Level3 : PathSegment<Level4> {
    data class LowDomainTerm(val string: String) : Level3()
    // ...
enum class Level4 : PathSegment<Nothing> {
    OptionallyAFeature, // ...
operator fun <Last : PathSegment<Child>, Child : PathSegment<*>> Path<Last>.div(child: Child): Path<Child> = Nested(this, child)

(Root / HighDomainTerm / MediumDomainTerm / LowDomainTerm("runtime value!") / OptionallyAFeature).segments ==
    listOf(Level1.HighDomainTerm, Level2.MediumDomainTerm, Level3.LowDomainTerm("runtime value!"), Level4.OptionallyAFeature)