The code with the class loader above gives you what you’ve asked for. Unfortunately not what you want. The jvm datatypes (classes, methods) are like OS level subroutine calls. They are required for the jvm to operate. That’s their design.
Unfortunately, it isn’t designed for consumer orchestration. The only time I’ve used it in production is to be able to load runtime classes that implement a sub-system interface. The consumer calls the public interface. Then, based on a rule, will load a specific implementation of the sub-system interfaces. Probably the most obvious use was to load different localizations of the subsystem based on localization rules or a different implementation for a MassPar computer than a mainframe.
In both cases, we could have included all of the implementations in a single implementation jar. But that jar would be massive and unwieldy. We couldn’t add new functions while the system was running. We’d have to stop the system and restart it with the new code.
In those cases, the consumer’s don’t change their code. The subsystem interface just hides the implementation. What you’re asking for is a tremendously finer grain.
Also scala isn’t java. It just compiles down to the jvm. No different than compiling to machine code (other than faster). The data structures and execution context don’t reflect your scala code. One can run Fortran codes on the same jvm. The execution support scala and Fortran. Reverse execution would be equally confusing for each language. The original compilers would also compile down to the .Net environment.
It can be done, but it isn’t what you want.