I think you’ve raised an important point here and one that deserves a good answer. It’s been a while since I looked at the manual but, as far as I know, we don’t have any real documentation that addresses this – which is particularly likely to cause confusion when everyone is to the Java-esque solution.
Generally speaking, Julia has been used quite widely and in very large (~100kloc) codebases, so it’s unlikely that it’s missing obvious features that would make this stuff very difficult. In most cases, it turns out that Julia handles this stuff fine – but perhaps take a different approach compared to other languages.
In this case, Julia uses “has-a” rather than “is-a” relationships. Trivial example:
makenoise(n::Noise) = println(n.loud ? uppercase(n.sound) : n.sound)
Dog(wetnose) = Dog(wetnose, Noise("woof", true))
Cat(longwhiskers) = Cat(longwhiskers, Noise("purr", false))
This approach is going to be weird for those who’ve used more classic inheritance models, but it’s arguably more general and powerful. You can inherit behaviour and fields from multiple sources and combine them with total control. Having to explicitly forward methods is a line or two of extra boilerplate (annoying I know ) but that’s relatively minimal. Here’s a post I wrote where I go over a more complex architecture in excruciating detail.
It may take a while to get used to this but I think it should address your underlying issue. It’s been a powerful way to handle all the cases I’ve come across. If you come across a case where that pattern isn’t working for you, we’d be more than happy to help figure out either how to make it work or what improvements the language needs to support it.