# What is the reason behind Smart Cast being impossible to perform when referenced class is in another module?

**URL:** <https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201>\
**Category:** Language Design\
**Created:** [January 5, 2017, 8:52am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201 "2017-01-05T08:52:02Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![geofrank](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/geofrank/32/5625_2.png) [@geofrank](https://discuss.kotlinlang.org/u/geofrank)\
**Post date:** [October 19, 2018, 10:14am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/21 "2018-10-19T10:14:49Z")

</div>

@yole Ref discussion with @atomcat1978, perhaps one solution would be to generate the extra type information at compile-time, and embed it in the binary (f.ex. in the META-INF folder of the JAR).

This idea was inspired by how TypeScript libraries often ship type declarations in addition to executable JS.

That being said, I have little insight into the inner workings of the Kotlin compiler / JVM, so it’s hard for me to say if it’s workable, or even a good idea.

---

<div class="post-metadata">

**Author:** ![yole](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/yole/32/1425_2.png) [@yole](https://discuss.kotlinlang.org/u/yole)\
**Post date:** [October 19, 2018, 11:07am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/22 "2018-10-19T11:07:23Z")

</div>

I’m not sure how you expect that generating extra information would help. It’s already possible to detect that a property is implemented as a direct access to a final field. The problem is that you can **change the implementation** , and this would invalidate the assumptions made when compiling the dependent module. Or do you suggest that the compiled code should access the metadata at runtime and refuse to function if the metadata differs from what existed when the module was compiled?

---

<div class="post-metadata">

**Author:** ![atomcat19781](https://avatars.discourse-cdn.com/v4/letter/a/7cd45c/32.png) [@atomcat19781](https://discuss.kotlinlang.org/u/atomcat19781)\
**Post date:** [October 19, 2018, 3:43pm UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/23 "2018-10-19T15:43:45Z")

</div>

Actually, the new `when` syntax is going to help a lot in this sense:

```auto
// another module:::
data class ClassInOtherModule(val name: String?)

// module using the code:::
val instance = ClassInOtherModule(null)

when (val name = instance.name) {
    null -> println("")
    else -> println(name)
}

```

---

<div class="post-metadata">

**Author:** ![fatjoe79](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/fatjoe79/32/4221_2.png) [@fatjoe79](https://discuss.kotlinlang.org/u/fatjoe79)\
**Post date:** [October 19, 2018, 4:53pm UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/24 "2018-10-19T16:53:42Z")

</div>

> [@atomcat19781](#):
>
> Actually, the new `when` syntax is going to help a lot in this sense.

Your example is equivalent to much shorter:

`println(instance.name ?: "")`

---

<div class="post-metadata">

**Author:** ![atomcat19781](https://avatars.discourse-cdn.com/v4/letter/a/7cd45c/32.png) [@atomcat19781](https://discuss.kotlinlang.org/u/atomcat19781)\
**Post date:** [October 19, 2018, 5:34pm UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/25 "2018-10-19T17:34:52Z")

</div>

It was an oversimplified example. Read the thread, and than you’ll see what I meant. Certainly I would not just write out the name property, but do some more stuff in a real life example.

```auto
when(val name = instance.name) {
   null -> doSomedefault()
   else -> callABuisnessMethod(name)
}

```

Previously it was not possible, you had to use the evil `!!` operator like this:

```auto
when(instance.name) {
   null -> doSomedefault()
   else -> callABuisnessMethod(instance.name!!) // since name is a public API property
}

```

You can solve this one with let as well, however, I think, the when version reads easier.

```auto
instance.name?.let {
   callABuisnessMethod(it)
} ?: doSomeDefault()

```

---

<div class="post-metadata">

**Author:** ![miguelvargas](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/miguelvargas/32/3308_2.png) [@miguelvargas](https://discuss.kotlinlang.org/u/miguelvargas)\
**Post date:** [November 13, 2018, 11:49pm UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/26 "2018-11-13T23:49:45Z")

</div>

This is caused by the poor language design decision to add val get(). Without val get() kotlin could have more strongly declared that `val` means immutable, now it only means “read-only”. val get()'s are not worth the trouble they cause. In my team we have a convention to always declare functions for non-immutable data. It is a bug in the language in my opinion. I would support a breaking change to get rid of val get()s.

---

<div class="post-metadata">

**Author:** ![Wasabi375](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/wasabi375/32/4741_2.png) [@Wasabi375](https://discuss.kotlinlang.org/u/Wasabi375)\
**Post date:** [November 14, 2018, 12:20am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/27 "2018-11-14T00:20:35Z")

</div>

How exactly do you propose to change `val` to work? It has to be compatible with classes written in java. There is no way of ensuring immutability when working with third party libraries. You would need to drop java interop at least to make this change work.

Also it’s quite a common practise to have a public getter with private/protected setters. Maybe you don’t do that in your team, but I don’t see why kotlins property syntax should not be able to support this and I would most certainly not consider this a bug in the language.

If you propose to add a new keyword for immutable fields, I would like that but maybe that should be a different topic here (as it has nothing to do with the original question).

---

<div class="post-metadata">

**Author:** ![miguelvargas](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/miguelvargas/32/3308_2.png) [@miguelvargas](https://discuss.kotlinlang.org/u/miguelvargas)\
**Post date:** [November 14, 2018, 1:52am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/28 "2018-11-14T01:52:39Z")

</div>

I would propose to get rid of all the magic around property access and getter functions. A getter function would have no magic, just like java. Property access would just be naked access to the field. Same with property delegates, I don’t understand what we gain by complicating properties instead of just using functions.

---

<div class="post-metadata">

**Author:** ![fatjoe79](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/fatjoe79/32/4221_2.png) [@fatjoe79](https://discuss.kotlinlang.org/u/fatjoe79)\
**Post date:** [November 14, 2018, 7:55am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/29 "2018-11-14T07:55:56Z")

</div>

As you write yourself, you can already decide to declare functions to access private properties. By removing the properties feature from the language, we can’t gain immutability as you claim it.

---

<div class="post-metadata">

**Author:** ![Jonathan.Haas](https://avatars.discourse-cdn.com/v4/letter/j/c68b51/32.png) [@Jonathan.Haas](https://discuss.kotlinlang.org/u/Jonathan.Haas)\
**Post date:** [November 15, 2018, 9:57am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/30 "2018-11-15T09:57:36Z")

</div>

If `val` would mean the same as `(public) final <type>` in Java, the reference would be immutable and smartcasts could work. I’m with @miguelvargas here. Of course, implementing fields using getters is good style and for that, smartcasts wouldn’t work.

---

<div class="post-metadata">

**Author:** ![fatjoe79](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/fatjoe79/32/4221_2.png) [@fatjoe79](https://discuss.kotlinlang.org/u/fatjoe79)\
**Post date:** [November 15, 2018, 10:35am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/31 "2018-11-15T10:35:51Z")

</div>

> [@Jonathan.Haas](#):
>
> If `val` would mean the same as `(public) final <type>` in Java, the reference would be immutable and smartcasts could work

That’s not the reason why it does not work. In fact, smart casts on val properties DO work. But only if the accessed property is in the same module as the accessing code.

---

<div class="post-metadata">

**Author:** ![Jonathan.Haas](https://avatars.discourse-cdn.com/v4/letter/j/c68b51/32.png) [@Jonathan.Haas](https://discuss.kotlinlang.org/u/Jonathan.Haas)\
**Post date:** [November 15, 2018, 11:03am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/32 "2018-11-15T11:03:26Z")

</div>

That is exactly the reason why they don’t work. And in the local module the smartcasts only work because there Kotlin can be sure that you’re not implementing them using `get()`. In other modules, kotlin can’t be sure about that because replacing a simple val with a custom getter isn’t a breaking change.

---

<div class="post-metadata">

**Author:** ![pdvrieze](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/pdvrieze/32/1882_2.png) [@pdvrieze](https://discuss.kotlinlang.org/u/pdvrieze)\
**Post date:** [November 15, 2018, 1:05pm UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/33 "2018-11-15T13:05:51Z")

</div>

More importantly, changes in classes can be made even at runtime (using classloaders). Even the assumption that within the module the class is stable somewhat exposes the system to ABI change related bugs.

---

<div class="post-metadata">

**Author:** ![Tim\_van\_der\_Leeuw.1](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/tim_van_der_leeuw.1/32/9155_2.png) [@Tim\_van\_der\_Leeuw.1](https://discuss.kotlinlang.org/u/Tim_van_der_Leeuw.1)\
**Post date:** [November 15, 2018, 2:09pm UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/34 "2018-11-15T14:09:54Z")

</div>

Or Hibernate-like bytecode manipulation.

---

<div class="post-metadata">

**Author:** ![rogve22](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@rogve22](https://discuss.kotlinlang.org/u/rogve22)\
**Post date:** [December 11, 2018, 3:04am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/35 "2018-12-11T03:04:17Z")

</div>

Thanks. I use the first when version on my JPA repository method.

It is more readable to check null.

---

<div class="post-metadata">

**Author:** ![AlexTrotsenko](https://avatars.discourse-cdn.com/v4/letter/a/ecd19e/32.png) [@AlexTrotsenko](https://discuss.kotlinlang.org/u/AlexTrotsenko)\
**Post date:** [June 10, 2020, 10:07am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/36 "2020-06-10T10:07:26Z")

</div>

@yole do you think it would be possible to consider adding some kind of configuration/compile time option to explicitly declare that you own certain modules in multi-module project and you are responsible not to break such contract and compile all projects together (e.g. gradle/maven) ?

It might make sense to have such option and to tell the compiler “I know better and it’s me to blame if it’s not the case”.

From my point of view it’s aligned with “being pragmatic” approach and similar to existing features like `!!` or `late init var`, etc.  
Does it make sense to you?

---

<div class="post-metadata">

**Author:** ![klesniewski](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/klesniewski/32/8324_2.png) [@klesniewski](https://discuss.kotlinlang.org/u/klesniewski)\
**Post date:** [February 8, 2021, 9:43am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/37 "2021-02-08T09:43:22Z")

</div>

It was already mentioned here a few times, last time in @AlexTrotsenko comment. Cannot we instruct compiler, that we “trust” certain modules and take the responsibility if things don’t work at runtime? It is pretty annoying, when in my multi-project build I have to choose between benefiting from smart casts and breaking down codebase into separate projects for clean reuse. In my case, I know the code is always compiled together and put into Docker container where it won’t change and yet compiler won’t let me benefit from smart cast because of theoretical possibility, which does not happen in practice.

I see though, how this is a real problem when using external libraries or even when using library from the same multi-project build in another library, as we cannot guarantee that both modules will resolve to the same version in the project they are used.

I’m curious what’s your opinion on it @yole. How do you see such compiler option for some projects?

---

<div class="post-metadata">

**Author:** ![yole](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/yole/32/1425_2.png) [@yole](https://discuss.kotlinlang.org/u/yole)\
**Post date:** [February 8, 2021, 11:47am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/38 "2021-02-08T11:47:55Z")

</div>

For the record I’m no longer involved in the design of Kotlin. My personal opinion is that adding command-line switches for drilling holes in the type system is a bad idea and should not be done; however, I’m not the one who you need to convince if you want to see some changes here.

---

<div class="post-metadata">

**Author:** ![gmk57](https://avatars.discourse-cdn.com/v4/letter/g/4491bb/32.png) [@gmk57](https://discuss.kotlinlang.org/u/gmk57)\
**Post date:** [July 6, 2021, 8:46am UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/40 "2021-07-06T08:46:52Z")

</div>

See also corresponding [YouTrack issue](https://youtrack.jetbrains.com/issue/KT-39223).

---

<div class="post-metadata">

**Author:** ![alamothe](https://avatars.discourse-cdn.com/v4/letter/a/c4cdca/32.png) [@alamothe](https://discuss.kotlinlang.org/u/alamothe)\
**Post date:** [August 8, 2021, 1:20pm UTC](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201/41 "2021-08-08T13:20:25Z")

</div>

It would be amazing to instruct the compiler to “trust” modules that we own (consider Gradle multi-project build).

Right now this is forcing us to put everything in a single module.

[Previous page](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201.md?page=1)

[Next page](https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201.md?page=3)
