https://kotlinlang.org logo
t

Twferrell

04/01/2020, 3:33 PM
Hi all, I have a strange one here... So I'm trying to build a DSL in Kotlin and came across a scenario where I want to combine a set of symbols that are currently dispersed in various different packages behind one single, new package namespace. That way the folks using my DSL to author their own scripts don't have to import symbols from so many different packages. I came up with one idea of using type aliases, but I have so many symbols, I don't want to duplicate these and hard code each alias for all the various entities (not very DRY and difficult to maintain). Example (let's say Alabama is an "object" extending from State) // Aliasing example: typealias Alabama = com.some.other.package.states.Alabama typealias Alaska = com.some.other.package.states.Alaska typealias Electronics = com.some.yet.another.package.products.Electronics ... // For DSL magic: infix fun State.eq(other: State) = this == other // Then within the DSL I have: package com.dsls import com.combined.symbols.* rules { when (state eq ALABAMA) { true -> doSomething... false -> doSomethingElse... } }
s

Shawn

04/01/2020, 3:47 PM
so, what’s your question?
t

Twferrell

04/01/2020, 3:52 PM
Ah, sorry. Yeah, so are there any language tricks I might not be aware of that could allow me to consolidate all those symbols behind one package without having to alias each one individually?
Maybe something similar to how I would do it in Typescript.
s

Shawn

04/01/2020, 4:01 PM
My first instinct is to say no, since this sort of thing kinda runs counter to the mostly-explicit nature of import/package qualification I’d say Kotlin has
How exactly would you do it in TypeScript out of curiosity? Some kind of wildcard import and aliasing that gets evaluated at transpile time or something?
t

Twferrell

04/01/2020, 4:18 PM
Sure, so in Typescript, if you have a folder which contains an index.ts file you can consolidate other exported objects that might live in various other namespaces, behind that single namespace. Like this...
export * from './some-namespace/some.component'; export * from './some-other-namespace/some-other.component'; export * from './yet-another-namespace/yet-another.component'; export * from './some.module';
This may be easier to read.
s

Shawn

04/01/2020, 4:22 PM
Ahh, I see
I’m pretty confident that this isn’t something Kotlin supports. Like you said earlier, the
typealias
approach is definitely brittle and I’d argue the JB folks would consider the wildcard export approach also kinda brittle — you could definitely just recompile a project without pinned dependencies and then accidentally present a different “API” to your consumers
t

Twferrell

04/01/2020, 4:30 PM
Yeah, it's not a deal breaker. I was just trying to think of an easy way to hide things a bit better for the DSL users where they could just import one wildcard namespace without having to know details of where the underlying symbols actually live. Thanks though for helping me think through it.
👍 1
r

Ruckus

04/01/2020, 6:38 PM
If I may add my $0.02, "don't have to import symbols from so many different packages" is kind of pointless to optimize for in Kotlin (by design). It's assumed you'll be working in a reasonably well featured IDE (most likely IntelliJ), which should handle imports for you. You really shouldn't need to be concerned with them at all.
Granted, whether you agree with that sentiment is another matter entirely, but it's important to keep in mind that it is one of the key driving factors in how the language is designed and meant to be used.
d

David Eriksson

04/01/2020, 7:54 PM
I think that it could be a feature that you do not couple all symbols hard to the DSL.
p

psh

04/03/2020, 3:59 AM
Twferrell - thinking outside the box for a moment here. (and I mean WAY outside! 🙂 ) Have you considered how tools like Dagger and Room work? They both allow you to specify an interface / abstract class and they contain a compile-time annotation processor that writes a whole bunch of code for you. So, for instance, if you had an interface annotated with a marker annotation that your processor cares about you would be able to generate concrete classes that are (in some way) based on the information gleaned from the interface. The interface would be the equivalent of your typescript file, and kapt would be the analog of your typescript compiler. You’d be able to generate code using kotlinPoet for type aliases. Usually this kind of code generation happens during compile time of an app, but I’m sure you would utilize it to help generate code that you then package up with your DSL.
2 Views