- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Time to encourage meaningful type parameter names? Discuss
This comes from thinking about the alleged complexity of Scala (others' arguments have convinced me it is a real problem in the corporate world), my own experiences as I start to penetrate a little bit of the "inner core" of Scala, and most of all, trying to be productive and ask, "Are there simple ways to mitigate the complexity problem?" (Assuming you believe it is a problem.)
First, consider the following method:
def someMeaningfulName(x: Int, y: String, z: Long) {...}
I don't know about you, but I have never worked in an environment where this would be considered acceptable code (unless x, y, and z actually had special meaning in the problem space). I think it's a given that good software engineering demands meaningful variable names, both internal and visible.
Now consider the following type signature:flatMap [B, That] (f: (A) ⇒ GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
There are three type parameters, A, B, and That. None are meaningful. Due to the fortunate inclusion of f: in the type, it's fairly easy to figure out the meanings of A and B. We can finally figure out the meaning of That when we reach the end of the line, at which point we need to reread the entire line to put everything together. (OK, you may not. I do, and I submit that most programmers will need to do so once or more.)
In fairness, there was a valid reason for using one-char type param back when type params were new; the declarations were simply (usually container classes), and the one-char rule made it obvious what was a type param and what was an actual type. Note the above def'n has already violated the one-char rule, without really adding value.
How about this
flatMap [resultElementType, resultType] (f: (inputElementType) ⇒ GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType], resultElementType, resultType]): resultType
This is much more verbose, but to someone unaccustomed to Scala collections, it is also much clearer. I've taken the liberty of using initial lowercase to denote a parameter rather than an actual type; I believe this is illegal, but I simply wanted to show how things could be made more readable.
If you're an experienced Scala user, this may not seem a big deal, just extra characters. Consider the process of reading the type signature from left to right, understanding as we go:
flatMap [B, That]
vs. flatMap [resultElementType, resultType]
The second has immediate meaning. The first does not.
The example I chose was mid-level in complexity--it is as the top of what a Scala novice should encounter, but nowhere near as complex as one might encounter in Scala internals or scalaz.
I believe that encouraging meaninful type parameter names would help the perceived "Scala complexity" problem in two ways. First, it makes the more complex "beginner's" Scala signatures more immediately understandable to beginners. Second, it make intellectually sophisticated Scala code more acceptable to the mainstream by making it more readable.
OK, that's it. Discuss :-)
Thanks,Ken
First, consider the following method:
def someMeaningfulName(x: Int, y: String, z: Long) {...}
I don't know about you, but I have never worked in an environment where this would be considered acceptable code (unless x, y, and z actually had special meaning in the problem space). I think it's a given that good software engineering demands meaningful variable names, both internal and visible.
Now consider the following type signature:flatMap [B, That] (f: (A) ⇒ GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
There are three type parameters, A, B, and That. None are meaningful. Due to the fortunate inclusion of f: in the type, it's fairly easy to figure out the meanings of A and B. We can finally figure out the meaning of That when we reach the end of the line, at which point we need to reread the entire line to put everything together. (OK, you may not. I do, and I submit that most programmers will need to do so once or more.)
In fairness, there was a valid reason for using one-char type param back when type params were new; the declarations were simply (usually container classes), and the one-char rule made it obvious what was a type param and what was an actual type. Note the above def'n has already violated the one-char rule, without really adding value.
How about this
flatMap [resultElementType, resultType] (f: (inputElementType) ⇒ GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType], resultElementType, resultType]): resultType
This is much more verbose, but to someone unaccustomed to Scala collections, it is also much clearer. I've taken the liberty of using initial lowercase to denote a parameter rather than an actual type; I believe this is illegal, but I simply wanted to show how things could be made more readable.
If you're an experienced Scala user, this may not seem a big deal, just extra characters. Consider the process of reading the type signature from left to right, understanding as we go:
flatMap [B, That]
vs. flatMap [resultElementType, resultType]
The second has immediate meaning. The first does not.
The example I chose was mid-level in complexity--it is as the top of what a Scala novice should encounter, but nowhere near as complex as one might encounter in Scala internals or scalaz.
I believe that encouraging meaninful type parameter names would help the perceived "Scala complexity" problem in two ways. First, it makes the more complex "beginner's" Scala signatures more immediately understandable to beginners. Second, it make intellectually sophisticated Scala code more acceptable to the mainstream by making it more readable.
OK, that's it. Discuss :-)
Thanks,Ken










Re: Re: Time to encourage meaningful type parameter names? Dis
On Thursday 17 November 2011, Kenneth McDonald wrote:
> .... Why not require that every function name be the
> min number of characters to uniquely represent it-- ...
Please show us how to quantify "... the min number of characters
[required] to uniquely represent [every function]."
And tell us how that relates to the concept of functional abstraction.
> Ken
Randall Schulz
Re: Re: Time to encourage meaningful type parameter names? Dis
The observation was intended semiseriously...why represent _anything_ with a number of characters greater than that necessary to guarantee a unique representation? Obviously, because further characters can add (for lack of a better term) meta-semantic meaning.
Ken
On Saturday, November 19, 2011 3:19:14 PM UTC-6, Randall Schulz wrote:
Re: Re: Time to encourage meaningful type parameter names? Dis
On Saturday 19 November 2011, Kenneth McDonald wrote:
> I was assuming that the number of functions are known (or at least
> bounded), in which case the calculation is trivial.
I believe there are aleph_0 distinct discrete functions. Probably
aleph_1 distinct functions over continuous variables. Those are just
guesses, though...
> The observation was intended semiseriously...why represent _anything_
> with a number of characters greater than that necessary to guarantee
> a unique representation? Obviously, because further characters can
> add (for lack of a better term) meta-semantic meaning.
I did not detect the (implied) semi-humor. Sorry...
I don't know what "meta-semantic meaning" might be, but humans do
clearly benefit greatly from whatever connotative value they can derive
from the particular choice of symbols even though those symbols are, in
fact, entirely arbitrary.
> Ken
Randall Schulz
> On Saturday, November 19, 2011 3:19:14 PM UTC-6, Randall Schulz wrote:
> > On Thursday 17 November 2011, Kenneth McDonald wrote:
> > > .... Why not require that every function name be the
> > > min number of characters to uniquely represent it-- ...
> >
> > Please show us how to quantify "... the min number of characters
> > [required] to uniquely represent [every function]."
> >
> > And tell us how that relates to the concept of functional
> > abstraction.
> >
> > > Ken
> >
> > Randall Schulz
Re: Re: Time to encourage meaningful type parameter names? Dis
You wonder where one-letter identifiers are constantly coming from ? Just go to arxiv.org and open any random math paper.
You won't see any identifiers longer than 3 characters, but they are doing pretty good job with them for the last couple hundred of years :-)
On Thu, Nov 17, 2011 at 5:14 PM, Kenneth McDonald <ykkenmcd [at] gmail [dot] com> wrote:
Re: Re: Time to encourage meaningful type parameter names? Dis
On 17 November 2011 18:34, Alex Repain <alex [dot] repain [at] gmail [dot] com> wrote:
The Map data structure is intrinsically associated with the concept of a data structure that represents some key instances drawn from a key set conforming to a Key type that 'map to' some value instances drawn from a value set/bag conforming to a Value type. If a person doesn't understand Key/Value (or K/V) because they don't know what a Map is, then they need to find out what a Map is. The issue you're raising in this case isn't with the naming of the type parameters, but that the entire concept modelled by the Map isn't known to the user. Once they understand the Map abstraction, it's much easer for a normal programmer to look at signatures with the type parameters Key/Value (or K/V) than A/B and associate this back to the Map abstraction. Normal people find names and mnemonics easier to remember than random letters. We can find any amount of published literature that demonstrates this experimentally, and probably also papers that specifically dissect out what sub-population this doesn't hold for (hint - this sub-population is not over-represented in that which is also your average programmer, certainly not to the point that you can discard using informative names in APIs aimed at average programmers).
Matthew
--
Dr Matthew PocockIntegrative Bioinformatics Group, School of Computing Science, Newcastle Universitymailto: turingatemyhamster [at] gmail [dot] com gchat: turingatemyhamster [at] gmail [dot] commsn: matthew_pocock [at] yahoo [dot] co [dot] uk irc.freenode.net: drdozerskype: matthew.pococktel: (0191) 2566550mob: +447535664143
Re: Re: Time to encourage meaningful type parameter names? Dis
The assumption that _your_ domains and ranges should command single-char status is false and harmful.
Ken
Re: Re: Time to encourage meaningful type parameter names? Dis
2011/11/20 Kenneth McDonald <ykkenmcd [at] gmail [dot] com>
I agree with you. I was drawing the distinction between using V or Value as opposed to B for Value. The distinction between using a mnemonic vs a full name is comparatively small compared to using an intentionally meaningless letter. However, I'd agree with you that personally I'd prefer to see the full name.
Agreed, especially if they leak out of my API.
Matthew
--
Dr Matthew PocockIntegrative Bioinformatics Group, School of Computing Science, Newcastle University mailto: turingatemyhamster [at] gmail [dot] comgchat: turingatemyhamster [at] gmail [dot] com msn: matthew_pocock [at] yahoo [dot] co [dot] ukirc.freenode.net: drdozerskype: matthew.pocock tel: (0191) 2566550mob: +447535664143
RE: Re: Time to encourage meaningful type parameter names? Dis
Date: Thu, 17 Nov 2011 19:59:41 +0000
Subject: Re: [scala-debate] Re: [scala-user] Time to encourage meaningful type parameter names? Discuss
From: turingatemyhamster [at] gmail [dot] com
The Map data structure is intrinsically associated with the concept of a data structure that represents some key instances drawn from a key set conforming to a Key type that 'map to' some value instances drawn from a value set/bag conforming to a Value type
Re: Re: Time to encourage meaningful type parameter names? Dis
Why did you choose A and B there? A and B don't scream out "function" to me. Function1 uses T1 and R. Map[K,V] extends K => V is equally informative. If you had Map[T1,R], that might provoke some serious head-scratching--T1? R? What? Why are they named _that_ way instead of something obvious or utterly generic?
But the real drawback is that the fraction of time you care that Map extends Function1 is small compared to the fraction of the time that you care where the key is and where the value is.
It's not like names have no point at all. We forget things; if we always remembered, we wouldn't need type checking. Otherwise, we could just declare
abstract class A[B] {
def b[C](c: B => C): A[C]
def e(f: B): B
def g[D](h: D)(i: B => D): D
}
which one can figure out uses for by pondering the type signatures. Just because one can take the opposite approach of overly-long and overly-specific names and end up with something even more atrocious (to my mind):
abstract class WrapperForSomethingThatMayNotExist[TypeOfThingThatMayNotExist] {
def transformWithFunctionIfPresent(
transformerFunction: TypeOfThingThatMayNotExist => TypeToTransformTo
): WrapperForSomethingThatMayNotExist[TypeToTransformTo]
def getWrappedObjectIfPresentOrDefaultIfNot(
defaultValue: TypeOfThingThatMayNotExist
): TypeOfThingThatMayNotExist
def getTransformedValueIfThingExistsOrDefaultIfNot[TypeOfThingToTransformToOrReturn] (
defaultValue: TypeOfThingToMapToOrReturn
) (
transformerFunction: TypeOfThingThatMayNotExist => TypeOfThingToTransformToOrReturn
): TypeOfThingToTransformToOrReturn
}
does not mean that meaningless names are ideal.
Compact but mnemonically useful names are the way to go.
--Rex
Re: Re: Time to encourage meaningful type parameter names? Dis
Well, fair point with Map[K, V]--I'm with you there!
On Thu, Nov 17, 2011 at 10:21 AM, Matthew Pocock
wrote:
> Yes.... Wouldn't Map[K, V] or Map[Key, Value] be more self-explanatory?
> Peace.
>
> 2011/11/17 Michael Schmitz
>>
>> We already have great entries in the scaladoc about type parameters.
>>
>> http://www.scala-lang.org/api/current/index.html#scala.collection.Map
>>
>> Peace. Michael
>>
>>
>> 2011/11/17 Daniel Sobral :
>> > 2011/11/17 √iktor Ҡlang :
>> >>
>> >>> > trait Graph[Node, Edge] <--- Looks great to me
>> >>>
>> >>> Except you just killed Node and Edge as trait/class names. At the very
>> >>> least, I'd call them ANode and AnEdge.
>> >>
>> >> trait Graph[N/*ode*/, E/*dge*/]
>> >
>> > Won't show up on Scaladoc, so what's the point? Nope, I still prefer
>> > ANode and AnEdge. :-)
>> >
>> > --
>> > Daniel C. Sobral
>> >
>> > I travel to the future all the time.
>> >
>
>
>
> --
> Dr Matthew Pocock
> Integrative Bioinformatics Group, School of Computing Science, Newcastle
> University
> mailto: turingatemyhamster [at] gmail [dot] com
> gchat: turingatemyhamster [at] gmail [dot] com
> msn: matthew_pocock [at] yahoo [dot] co [dot] uk
> irc.freenode.net: drdozer
> skype: matthew.pocock
> tel: (0191) 2566550
> mob: +447535664143
>
Re: Re: Time to encourage meaningful type parameter names? Dis
Ken
Re: Re: Time to encourage meaningful type parameter names? Dis
Re: Re: Time to encourage meaningful type parameter names? Dis
On Thu, Nov 17, 2011 at 13:35, Simon Ochsenreither
wrote:
> Afaik C# prefixes type parameters with T and return type parameters with R
> ... but they also use I as a prefix for interfaces. The last holdout of
> Hungarian notation?
You should see that Uncle Bob has to say about prefixing interfaces
with I. Pretty funny! :-)
Re: Re: Time to encourage meaningful type parameter names? Dis
Ken
Re: Time to encourage meaningful type parameter names? Discuss
On Thu, Nov 17, 2011 at 11:48 AM, Matthew Pocock <turingatemyhamster [at] gmail [dot] com> wrote:
--
Viktor Klang
Akka Tech LeadTypesafe - Enterprise-Grade Scala from the Experts
Twitter: @viktorklang
RE: Time to encourage meaningful type parameter names? Discuss
trait Functor[F[_]] { def fmap[A, B](f: Functor[A], g: A => B): F[B] }
Then:
def Function1Functor[X] = new Functor[({type l[a]=X => a})#l] { def fmap[A, B](f: X => A, g: A => B): X => B = f andThen g }
Admittedly the collection library's map method "is not map" (as Tony says: http://stackoverflow.com/questions/1722726/is-the-scala-2-8-collections-library-a-case-of-the-longest-suicide-note-in-hist/1735694#1735694) but by tying the names of the type parameters down so specifically, it may be the case that the user misses an important abstraction
Chris
Date: Thu, 17 Nov 2011 12:12:48 +0100
Subject: Re: [scala-user] Time to encourage meaningful type parameter names? Discuss
From: viktor [dot] klang [at] gmail [dot] com
To: turingatemyhamster [at] gmail [dot] com
CC: tmorris [at] tmorris [dot] net; scala-user [at] googlegroups [dot] com
I think Tony's point wass that the higher the abstraction the less specific the name can be.
On Thu, Nov 17, 2011 at 11:48 AM, Matthew Pocock <turingatemyhamster [at] gmail [dot] com> wrote:
--
Viktor Klang
Akka Tech LeadTypesafe - Enterprise-Grade Scala from the Experts
Twitter: @viktorklang
Re: Time to encourage meaningful type parameter names? Discuss
- because they will appear repeatedly across your code when you write generic methods / traits, and it's already painful to write them in single letters
- because they should be capitalised to distinguish them from values, and hence they appear with visual contrast to class names which are also capitalized
- because they are read along with their carriers. e.g. `List[A]` obviously is a list of elements, where variable `a` has no meaning.
On 17 Nov 2011, at 01:09, Ken McDonald wrote:
> . Long names hurt eyes.
>
> D.
>
> So long variable names hurt eyes?
>
> This is a serious question. Why are long variable names good, and long type parameter names bad?
>
> Ken
>
>
>
Re: Time to encourage meaningful type parameter names? Discuss
Obviously I'm in favor of meaningful type parameter names, otherwise, I wouldn't have posted the original article. Even correcting for this bias, I don't believe your counterclaims stand up to scrutiny. Please don't take this as a personal attack. I am honestly trying to understand (and possibly change) the convention that IMHO partially prevents me from understanding complex type signatures as I delve deeper into Scala.
FWIW, I believe that the cost (extra characters) of providing meaningful type parameter names is inherently very low when compared to the cost of not providing them (meaning that the reader must infer the "meaning" of a type parameter). If you do not agree with this to at least some degree, we are axiomatically in conflict. This doesn't mean I despise your position :-). I just don't see any point in wasting bandwidth on differences that are fundamentally a matter of faith, not logic.
Cheers,Ken
On Wednesday, November 16, 2011 7:13:43 PM UTC-6, Sciss wrote:
Re: Time to encourage meaningful type parameter names? Discuss
On 17 Nov 2011, at 03:08, Ken McDonald wrote:
> - IDEs mean you do not have to type the full name every time.
( i type variable names and type names preferably without an autocompletion popup showing. )
> - ??? I don't understand your second objection.
T Abstract Type Member
Class Class
value value
easy to distinguish.
List[List[A]] - -> List a class, A a generic type parameter -- a list of a list of elements (A). simple
List[elemType] -> woopa, gotta realize there are square brackets here and no parentheses
> - I think in this point you're arguing for me rather than against me. List[A] may be "obviously" bet a set of elements, but my whole point was that _as type signatures have become more complex_, the "single-char type parameter" convention has lost validity. As for variable 'a' has no meaning: Show me one example, _anywhere_ of a variable that has _no_ meaning. Maybe in Prolog, but that's arguable.
def add( elem: A ) // yes
def add( a: Elem ) // no
why would you juggle around inside the method body with 'a' when you can have 'elem' which is clear.
here some code i'm just writing in this moment:
trait AssocEntry[ S <: Sys[ S ], A ] extends Entry[ S ] {
def value( implicit tx: S#Tx ) : A
def append( value: A )( implicit tx: S#Tx ) : AssocEntry[ S, A ]
def prepend( value: A )( implicit tx: S#Tx ) : AssocEntry[ S, A ]
}
versus
trait AssocEntry[ system <: Sys[ system ], element ] extends Entry[ system ] {
def value( implicit tx: system#transaction ) : element
def append( value: element )( implicit tx: system#transaction ) : AssocEntry[ system, element ]
def prepend( value: element )( implicit tx: system#transaction ) : AssocEntry[ system, element ]
}
honestly, i doubt anyone wants to either read or write it this way.
best, -sciss-
Re: Time to encourage meaningful type parameter names? Discuss
On 17 November 2011 03:21, Sciss <contact [at] sciss [dot] de> wrote:
The 2nd version is much easier to understand at the expense of being more difficult to read. Remember, in an API, the type names are part of your documentation to other people. After reading your first version, I'm left none-the-wiser what A is. In the 2nd one, it's obvious. Given that we're dealing with systems and transactions, #Tx is understandable.
I have to say that I share the OPs experience. When I first came to scala, I found that the use of extremely generic type parameter names very confusing. They don't need to be SAs, but where it makes sense using a word rather than a letter would be a really good thing.
Matthew
--
Dr Matthew PocockIntegrative Bioinformatics Group, School of Computing Science, Newcastle Universitymailto: turingatemyhamster [at] gmail [dot] com gchat: turingatemyhamster [at] gmail [dot] commsn: matthew_pocock [at] yahoo [dot] co [dot] uk irc.freenode.net: drdozerskype: matthew.pococktel: (0191) 2566550mob: +447535664143
Re: Time to encourage meaningful type parameter names? Discuss
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Am 17.11.2011 11:46, schrieb Matthew Pocock:
comparing these alternatives:
>> trait AssocEntry[ S <: Sys[ S ], A ] extends Entry[ S ] {
>> def value( implicit tx: S#Tx ) : A
>> def append( value: A )( implicit tx: S#Tx ) : AssocEntry[ S, A ]
>> def prepend( value: A )( implicit tx: S#Tx ) : AssocEntry[ S, A ]
>> }
versus
>> trait AssocEntry[ system <: Sys[ system ], element ] extends Entry[
>> system ] {
>> def value( implicit tx: system#transaction ) : element
>> def append( value: element )( implicit tx: system#transaction ) :
>> AssocEntry[ system, element ]
>> def prepend( value: element )( implicit tx: system#transaction ) :
>> AssocEntry[ system, element ]
>> }
my impression is, that the second alternative is better understandable,
while reading the first time, when you have to understand what is going
on at all. But the first alternative is better readable when you started
working a bit with it, and only need to look up specific details.
It might look better in both cases, if you place the blanks correctly:
outside of the parentheses:
>> trait AssocEntry [S <: Sys [S], A] extends Entry [S] {
>> def value (implicit tx: S#Tx): A
>> def append (value: A) (implicit tx: S#Tx): AssocEntry [S, A]
>> def prepend (value: A) (implicit tx: S#Tx): AssocEntry [S, A]
>> }
versus
>> trait AssocEntry [system <: Sys [system], element] extends Entry [
>> system] {
>> def value (implicit tx: system#transaction): element
>> def append (value: element) (implicit tx: system#transaction):
>> AssocEntry [system, element]
>> def prepend (value: element) (implicit tx: system#transaction):
>> AssocEntry [system, element]
>> }
which is, how it is done in book setting with 500 years of experience in
readability.
Back to the topic: I think this is not something which is subjective or
something based on faith or taste. If you have to read the whole
trait-definition, because it is new for you, you're reading slowly,
token by token, and long lines with line breaks in them aren't
disturbing. But if you later look it up, and try to search something
with the eyes, they fly over the line, and are looking for the
structure, which is much better to get, if there are short and compact
structures.
Which would correspondent with beginners, preferring the second
approach, and people more used to the language preferring the first.
Re: Time to encourage meaningful type parameter names? Discuss
In my original post, I believe I made clear the fact that I was using initial lowercase as a presentation convenience, and not as part of the Scala language. What (if anything) should be done to differnetiate multichar type parameter names from valid type names is open to discussion. Wow, you couldn't be more wrong. (Don't mean to be offensive, but it's the truth.). The latter has some semantic meaning to me--not much, but some. The former has no meaning whatsoever. That's a difference of approximately infinity :-)
I just want to emphasize how serious I am about this. As far as I'm concerned, the first presentation is gibberish. The second doesn't let me understand the system, but it leads me in an appropriate direction. That's a huge difference!
Cheers,Ken
Re: Time to encourage meaningful type parameter names? Discuss
To be honest, I glaze over when I see the second signature but not the first.
On Wed, Nov 16, 2011 at 10:53 AM, Ken McDonald wrote:
> This comes from thinking about the alleged complexity of Scala (others'
> arguments have convinced me it is a real problem in the corporate world), my
> own experiences as I start to penetrate a little bit of the "inner core" of
> Scala, and most of all, trying to be productive and ask, "Are there simple
> ways to mitigate the complexity problem?" (Assuming you believe it is a
> problem.)
> First, consider the following method:
> def someMeaningfulName(x: Int, y: String, z: Long) {...}
> I don't know about you, but I have never worked in an environment where this
> would be considered acceptable code (unless x, y, and z actually had special
> meaning in the problem space). I think it's a given that good software
> engineering demands meaningful variable names, both internal and visible.
> Now consider the following type signature:
>
> flatMap [B, That] (f: (A)
> => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
>
> There are three type parameters, A, B, and That. None are meaningful. Due to
> the fortunate inclusion of f: in the type, it's fairly easy to figure out
> the meanings of A and B. We can finally figure out the meaning of That when
> we reach the end of the line, at which point we need to reread the entire
> line to put everything together. (OK, you may not. I do, and I submit that
> most programmers will need to do so once or more.)
> In fairness, there was a valid reason for using one-char type param back
> when type params were new; the declarations were simply (usually container
> classes), and the one-char rule made it obvious what was a type param and
> what was an actual type. Note the above def'n has already violated the
> one-char rule, without really adding value.
> How about this
>
> flatMap [resultElementType, resultType] (f: (inputElementType)
> => GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType],
> resultElementType, resultType]): resultType
>
> This is much more verbose, but to someone unaccustomed to Scala collections,
> it is also much clearer. I've taken the liberty of using initial lowercase
> to denote a parameter rather than an actual type; I believe this is illegal,
> but I simply wanted to show how things could be made more readable.
> If you're an experienced Scala user, this may not seem a big deal, just
> extra characters. Consider the process of reading the type signature from
> left to right, understanding as we go:
> flatMap [B, That]
>
> vs.
> flatMap [resultElementType, resultType]
>
> The second has immediate meaning. The first does not.
> The example I chose was mid-level in complexity--it is as the top of what a
> Scala novice should encounter, but nowhere near as complex as one might
> encounter in Scala internals or scalaz.
> I believe that encouraging meaninful type parameter names would help the
> perceived "Scala complexity" problem in two ways. First, it makes the more
> complex "beginner's" Scala signatures more immediately understandable to
> beginners. Second, it make intellectually sophisticated Scala code more
> acceptable to the mainstream by making it more readable.
> OK, that's it. Discuss :-)
>
> Thanks,
> Ken
>
Re: Time to encourage meaningful type parameter names? Discuss
On Wednesday, November 16, 2011 3:17:22 PM UTC-6, Michael Schmitz wrote:Could you be more specify: Why? Why is the second signature less readable than the first?
As always, this is a serious question, not intended to be contentious. If we can figure out why certain signatures are more readable to certain classes of people, that's and advance, Jah?
Thanks,Ken
Re: Time to encourage meaningful type parameter names? Discuss
On Wed, Nov 16, 2011 at 16:53, Ken McDonald wrote:
> This comes from thinking about the alleged complexity of Scala (others'
> arguments have convinced me it is a real problem in the corporate world), my
> own experiences as I start to penetrate a little bit of the "inner core" of
> Scala, and most of all, trying to be productive and ask, "Are there simple
> ways to mitigate the complexity problem?" (Assuming you believe it is a
> problem.)
> First, consider the following method:
> def someMeaningfulName(x: Int, y: String, z: Long) {...}
> I don't know about you, but I have never worked in an environment where this
> would be considered acceptable code (unless x, y, and z actually had special
> meaning in the problem space). I think it's a given that good software
> engineering demands meaningful variable names, both internal and visible.
> Now consider the following type signature:
>
> flatMap [B, That] (f: (A)
> => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
>
> There are three type parameters, A, B, and That. None are meaningful. Due to
> the fortunate inclusion of f: in the type, it's fairly easy to figure out
> the meanings of A and B. We can finally figure out the meaning of That when
> we reach the end of the line, at which point we need to reread the entire
> line to put everything together. (OK, you may not. I do, and I submit that
> most programmers will need to do so once or more.)
> In fairness, there was a valid reason for using one-char type param back
> when type params were new; the declarations were simply (usually container
> classes), and the one-char rule made it obvious what was a type param and
> what was an actual type. Note the above def'n has already violated the
> one-char rule, without really adding value.
> How about this
>
> flatMap [resultElementType, resultType] (f: (inputElementType)
> => GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType],
> resultElementType, resultType]): resultType
>
> This is much more verbose, but to someone unaccustomed to Scala collections,
> it is also much clearer. I've taken the liberty of using initial lowercase
> to denote a parameter rather than an actual type; I believe this is illegal,
> but I simply wanted to show how things could be made more readable.
> If you're an experienced Scala user, this may not seem a big deal, just
> extra characters. Consider the process of reading the type signature from
> left to right, understanding as we go:
> flatMap [B, That]
>
> vs.
> flatMap [resultElementType, resultType]
>
> The second has immediate meaning. The first does not.
> The example I chose was mid-level in complexity--it is as the top of what a
> Scala novice should encounter, but nowhere near as complex as one might
> encounter in Scala internals or scalaz.
> I believe that encouraging meaninful type parameter names would help the
> perceived "Scala complexity" problem in two ways. First, it makes the more
> complex "beginner's" Scala signatures more immediately understandable to
> beginners. Second, it make intellectually sophisticated Scala code more
> acceptable to the mainstream by making it more readable.
While this sounds reasonable, the more, let's say, "abstract"
abstractions are not particularly prone to good names, because they do
not refer to particulars.
Consider, for instance a Monad[M[_]], or a method that _takes_ a monad
"m" as argument. What is the type A of M[A] such that exists
Monad[M[_]]? It is not the "element type", because that really works
for collections that contains thing. If you apply it to a continuation
monad, it doesn't make much sense. And what do you call "m" except
"monad"?
This always remind me of something that I witnessed at college. As the
teacher explained some abstract concept in linear algebra, the class
was very quiet. Some student then decided enough was enough and
decided to try to get something more concrete out of the teacher. The
dialog went pretty much like this:
- Professor, I'm having trouble understanding this. Could you give as
an example?
- This _is_ an example.
- No, I mean, could you give an example with numbers?
- Oh, ok. Assume you have three numbers, a, b, and c...
Re: Time to encourage meaningful type parameter names? Discuss
I recommend applying the same heuristics you use for any names. The more concrete the concept, the more concrete the name should be..
Sent from my iPad
On Nov 16, 2011, at 2:18 PM, Daniel Sobral wrote:
> On Wed, Nov 16, 2011 at 16:53, Ken McDonald wrote:
>> This comes from thinking about the alleged complexity of Scala (others'
>> arguments have convinced me it is a real problem in the corporate world), my
>> own experiences as I start to penetrate a little bit of the "inner core" of
>> Scala, and most of all, trying to be productive and ask, "Are there simple
>> ways to mitigate the complexity problem?" (Assuming you believe it is a
>> problem.)
>> First, consider the following method:
>> def someMeaningfulName(x: Int, y: String, z: Long) {...}
>> I don't know about you, but I have never worked in an environment where this
>> would be considered acceptable code (unless x, y, and z actually had special
>> meaning in the problem space). I think it's a given that good software
>> engineering demands meaningful variable names, both internal and visible.
>> Now consider the following type signature:
>>
>> flatMap [B, That] (f: (A)
>> => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
>>
>> There are three type parameters, A, B, and That. None are meaningful. Due to
>> the fortunate inclusion of f: in the type, it's fairly easy to figure out
>> the meanings of A and B. We can finally figure out the meaning of That when
>> we reach the end of the line, at which point we need to reread the entire
>> line to put everything together. (OK, you may not. I do, and I submit that
>> most programmers will need to do so once or more.)
>> In fairness, there was a valid reason for using one-char type param back
>> when type params were new; the declarations were simply (usually container
>> classes), and the one-char rule made it obvious what was a type param and
>> what was an actual type. Note the above def'n has already violated the
>> one-char rule, without really adding value.
>> How about this
>>
>> flatMap [resultElementType, resultType] (f: (inputElementType)
>> => GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType],
>> resultElementType, resultType]): resultType
>>
>> This is much more verbose, but to someone unaccustomed to Scala collections,
>> it is also much clearer. I've taken the liberty of using initial lowercase
>> to denote a parameter rather than an actual type; I believe this is illegal,
>> but I simply wanted to show how things could be made more readable.
>> If you're an experienced Scala user, this may not seem a big deal, just
>> extra characters. Consider the process of reading the type signature from
>> left to right, understanding as we go:
>> flatMap [B, That]
>>
>> vs.
>> flatMap [resultElementType, resultType]
>>
>> The second has immediate meaning. The first does not.
>> The example I chose was mid-level in complexity--it is as the top of what a
>> Scala novice should encounter, but nowhere near as complex as one might
>> encounter in Scala internals or scalaz.
>> I believe that encouraging meaninful type parameter names would help the
>> perceived "Scala complexity" problem in two ways. First, it makes the more
>> complex "beginner's" Scala signatures more immediately understandable to
>> beginners. Second, it make intellectually sophisticated Scala code more
>> acceptable to the mainstream by making it more readable.
>
> While this sounds reasonable, the more, let's say, "abstract"
> abstractions are not particularly prone to good names, because they do
> not refer to particulars.
>
> Consider, for instance a Monad[M[_]], or a method that _takes_ a monad
> "m" as argument. What is the type A of M[A] such that exists
> Monad[M[_]]? It is not the "element type", because that really works
> for collections that contains thing. If you apply it to a continuation
> monad, it doesn't make much sense. And what do you call "m" except
> "monad"?
>
> This always remind me of something that I witnessed at college. As the
> teacher explained some abstract concept in linear algebra, the class
> was very quiet. Some student then decided enough was enough and
> decided to try to get something more concrete out of the teacher. The
> dialog went pretty much like this:
>
> - Professor, I'm having trouble understanding this. Could you give as
> an example?
> - This _is_ an example.
> - No, I mean, could you give an example with numbers?
> - Oh, ok. Assume you have three numbers, a, b, and c...
>
Re: Time to encourage meaningful type parameter names? Discuss
Cheers,Ken
Re: Time to encourage meaningful type parameter names? Discuss
Yes, a good teacher should be able to give good examples of any
abstract concept, and the first examples shown should be as simple as
possible and contain as few extraneous complications as possible,
preferably none. Human minds are not compilers, but some teachers seem
to think they are. Our thinking tends to start in concrete terms and
progress to generalization and abstraction, not the other way around.
I recall an undergraduate class that I took many years ago in
classical control theory. The instructor would write equations and
talk about damping, natural frequency, etc. I didn't have too much
problem with it, but at least one person in particular didn't seem to
have a clue what he was talking about. She ended up getting into a
nasty spat with him. All he had to do was to give a few simple
examples and explain what the terms meant *physically*, as opposed to
*mathematically*. But apparently his mode of thinking was so abstract
that it did not occur to him.
Take a look at the IEEE Transactions on Automatic Control sometime for
some extreme examples of this kind of thinking. It tends to be very
abstract and mathematical with few practical examples of how the
concepts can be applied. Some of the authors almost seem to consider
practical applications and examples to be trivial and beneath their
dignity to spend time on -- an excercise left for the student.
--Russ P.
On Nov 16, 11:18 am, Daniel Sobral wrote:
> On Wed, Nov 16, 2011 at 16:53, Ken McDonald wrote:
> > This comes from thinking about the alleged complexity of Scala (others'
> > arguments have convinced me it is a real problem in the corporate world), my
> > own experiences as I start to penetrate a little bit of the "inner core" of
> > Scala, and most of all, trying to be productive and ask, "Are there simple
> > ways to mitigate the complexity problem?" (Assuming you believe it is a
> > problem.)
> > First, consider the following method:
> > def someMeaningfulName(x: Int, y: String, z: Long) {...}
> > I don't know about you, but I have never worked in an environment where this
> > would be considered acceptable code (unless x, y, and z actually had special
> > meaning in the problem space). I think it's a given that good software
> > engineering demands meaningful variable names, both internal and visible.
> > Now consider the following type signature:
>
> > flatMap [B, That] (f: (A)
> > => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
>
> > There are three type parameters, A, B, and That. None are meaningful. Due to
> > the fortunate inclusion of f: in the type, it's fairly easy to figure out
> > the meanings of A and B. We can finally figure out the meaning of That when
> > we reach the end of the line, at which point we need to reread the entire
> > line to put everything together. (OK, you may not. I do, and I submit that
> > most programmers will need to do so once or more.)
> > In fairness, there was a valid reason for using one-char type param back
> > when type params were new; the declarations were simply (usually container
> > classes), and the one-char rule made it obvious what was a type param and
> > what was an actual type. Note the above def'n has already violated the
> > one-char rule, without really adding value.
> > How about this
>
> > flatMap [resultElementType, resultType] (f: (inputElementType)
> > => GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType],
> > resultElementType, resultType]): resultType
>
> > This is much more verbose, but to someone unaccustomed to Scala collections,
> > it is also much clearer. I've taken the liberty of using initial lowercase
> > to denote a parameter rather than an actual type; I believe this is illegal,
> > but I simply wanted to show how things could be made more readable.
> > If you're an experienced Scala user, this may not seem a big deal, just
> > extra characters. Consider the process of reading the type signature from
> > left to right, understanding as we go:
> > flatMap [B, That]
>
> > vs.
> > flatMap [resultElementType, resultType]
>
> > The second has immediate meaning. The first does not.
> > The example I chose was mid-level in complexity--it is as the top of what a
> > Scala novice should encounter, but nowhere near as complex as one might
> > encounter in Scala internals or scalaz.
> > I believe that encouraging meaninful type parameter names would help the
> > perceived "Scala complexity" problem in two ways. First, it makes the more
> > complex "beginner's" Scala signatures more immediately understandable to
> > beginners. Second, it make intellectually sophisticated Scala code more
> > acceptable to the mainstream by making it more readable.
>
> While this sounds reasonable, the more, let's say, "abstract"
> abstractions are not particularly prone to good names, because they do
> not refer to particulars.
>
> Consider, for instance a Monad[M[_]], or a method that _takes_ a monad
> "m" as argument. What is the type A of M[A] such that exists
> Monad[M[_]]? It is not the "element type", because that really works
> for collections that contains thing. If you apply it to a continuation
> monad, it doesn't make much sense. And what do you call "m" except
> "monad"?
>
> This always remind me of something that I witnessed at college. As the
> teacher explained some abstract concept in linear algebra, the class
> was very quiet. Some student then decided enough was enough and
> decided to try to get something more concrete out of the teacher. The
> dialog went pretty much like this:
>
> - Professor, I'm having trouble understanding this. Could you give as
> an example?
> - This _is_ an example.
> - No, I mean, could you give an example with numbers?
> - Oh, ok. Assume you have three numbers, a, b, and c...
>
> --
> Daniel C. Sobral
>
> I travel to the future all the time.
Re: Time to encourage meaningful type parameter names? Discuss
There is a startling improvement in the readability of your modified
method signature.
On Wed, Nov 16, 2011 at 1:53 PM, Ken McDonald wrote:
> Now consider the following type signature:
>
> flatMap [B, That] (f: (A)
> => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
>
> How about this
>
> flatMap [resultElementType, resultType] (f: (inputElementType)
> => GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType],
> resultElementType, resultType]): resultType
>
Re: Time to encourage meaningful type parameter names? Discuss
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Am 16.11.2011 20:12, schrieb Donald McLean:
> There is a startling improvement in the readability of your modified
> method signature.
>
> On Wed, Nov 16, 2011 at 1:53 PM, Ken McDonald wrote:
>> Now consider the following type signature:
>>
>> flatMap [B, That] (f: (A)
>> => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
>>
>> How about this
>>
>> flatMap [resultElementType, resultType] (f: (inputElementType)
>> => GenTraversableOnce[resultElementType])(implicit bf: CanBuildFrom[List[inputElementType],
>> resultElementType, resultType]): resultType
>>
>
So the resultType is a collection, a wrapper, some meta-type, we focus
on, but we could as well focus on the first param:
flatMap [OType, OWrapper] (f: (IType) => GenTraversableOnce [OType])
(implicit bf: CanBuildFrom [List [IType], OType, OWrapper]): OWrapper
is I/O common enough to be used for IN and OUT parameters? Since those
param types are always types, the word `type` is a bit of a redundancy,
isn't it? Let's try dropping it:
flatMap [O, OWrapper] (f: (I) => GenTraversableOnce [O])
(implicit bf: CanBuildFrom [List [I], O, OWrapper]): OWrapper
reversing the initial step, it would look like this (OE:= OutElement):
flatMap [OE, O] (f: (I) => GenTraversableOnce [OE])
(implicit bf: CanBuildFrom [List [I], OE, O]): O
The question is, which abbreviation is strong enough to be identified
easily, and used often enough to get used to it. By now, I learned
following conventions:
* T: used for Type in its abstract beauty, very useful if there is only
one type parameter.
* M: the almighty Monad or something, the Monad deals with
* A, B, C, ...: Actors in the order of their appearance.
I think some conventions might help, but meanwhile I prefer short - very
short - names for type parameters, because I'm a bit used to it. If I
see Some[A, B, That, C], I immediately suspect A, B and C to be
Type-Parameters, but `That` not so much. `That` ist nearly as
informative as `Something` or `Yaknow` - isn't it?
And I think there is no silver bullet naming scheme. In some context, I
and O might have strong associations coupled with them, so that they get
confusing there.