« Return to Thread: annotations or traits to better scale scala up
Hi!
[this is more or less a repost directly to Nabble, as the original post to
scala-lang.org didn't work properly, as I was told]
everybody will agree that Scala scales great from medium sized applications
to small scripts, much better than esp. Java does. I often hear that it
scales up to large systems just as well, but does it? I think it does, but
could it be even better?
[This became a long post. If you don't want to read all the blurb, skip
ahead to the [*]]
Scala has some very powerful features that alleviate you from a lot of
constantly considering best practices. For example: How many equals and
hashCode methods have you seen that are just plain wrong (with sometimes
very subtle effects)? Case classes do that for free (and a lot more)! How
many singletons have you seen that try to be, but are *not* thread safe?!?
Scala objects are so right out of the box!
Things like this help a lot in small and big systems alike; they only scale
"linearily", i.e. the amount of best practices you don't have to take into
account any more by using Scala, stays constant per line of code.
What really does make a difference, though, is that Scala allows you to take
best practices out of your business code and encapsulate them directly into
your frameworks... and this is especially important for big systems. A
seemingly trivial example is that you can move the best practice of using
the fully qualified class name for a logger into a very simple trait:
trait Logging {
import org.slf4j._
val logger: Logger = LoggerFactory.getLogger(this.getClass)
}
This is not possible in Java, and it makes a real difference!
Some tools and frameworks will just take some time to grow as the community
grows: Code formatters (more important to big systems that to small!), code
analysis tools, refactoring and other IDE support, to name just a few. BTW:
I don't think that the module system suggested by Martin in "the" book
replaces the need for a real dependency injection framework: It doesn't take
the different build/deploy/run stages into account properly; and it misses
one important point: 'inversion of control', i.e. changing from pull to
push. But it is an interesting starting point and time will show.
Maybe some things in the language and/or compiler deserve some more pushing
for Scala to better scale up. For example type inference is just great for
smaller projects and client code, but for frameworks I think it's a good
practice to annotate at least the return type of a method -- that additional
piece of directly available information can be of great help. Without it you
sometimes have to look several method calls deep and/or look very closely.
This best practice is adhered to in some Scala library classes (e.g. List),
but not in all (e.g. Either). I think it would be a great help, if you could
make the compiler issue a warning, if it infers the return type of a method
for you. An IDE could even be configured to automatically add it on save.
Another example for language things to scale up better: Some types are not
meant to be used in a certain position. For example a HashMap should not be
used as the type of a variable, just for construction! At least in the Java
world this is a best practice most programmers use.
[*]
To finally get to the point: There could be some annotations or traits or
even structural type that helped make some design aspects of a library
explicit. If you could make the compiler issue a warning or even an error
when violated, then the design of a library would not erode as quickly as it
often does and library evolution could become safer. [I don't like the names
I use here, they are just the first thing that came to my mind and not well
thought about, yet. Read them as placeholders only.] Here they are:
DontAssign: Like HashMap example above, this type is not meant for
variables, values, or return types. Just use it for construction. The
counterpart "DontInstantiate" is not required: Making a class abstract or
defining it as a trait is explicit enough.
DontExtend: This class is meant to just be called by client code; avoid the
much stronger coupling by implementing a trait or extending a class. This
privilege is left to the library itself.
DontCall: This class or trait is a callback for the client code to extend
and the library to call. Don't do that at home.
DontStore: You should not save instances of this class for a longer period
of time, be it to a database, to xml, or serialization to a file. Libraries
storing objects would have to somehow specify that they don't like such
types.
DontSerialize: Stronger than the above... the library is holding references
that would get lost (e.g. Hibernate). Libraries serializing objects would
have to somehow specify that they don't like such types. There generally
should be a way to decouple such objects.
Immutable: The class guarantees that it recursively has no variables and is
purely functional. (I think this is a must!)
Mutable (as in C++): An exception to the above, that is: A variable is
required for performance reasons (e.g. a cache), but the logical state of
the class remains unchanged.
Key: Instances of this class can be used e.g. as a key in a HashMap, i.e.
the class overloads == and hashCode.
More thinking would certainly turn up more, but what does the Scala
community think about the general point I tried to make? Do you agree that
it would relevantly improve the up-scaling of Scala?
Regards
Walter
--
View this message in context: http://www.nabble.com/annotations-or-traits-to-better-scale-scala-up-tp23845439p23845439.html
Sent from the Scala - Debate mailing list archive at Nabble.com.
« Return to Thread: annotations or traits to better scale scala up
| Free embeddable forum powered by Nabble | Forum Help |