{
  "$type": "site.standard.document",
  "canonicalUrl": "https://oli.zilla.org.uk/2011/02/19/scala-compiler-fictions-and-the-suprising-difficulties-asking-anyval-its-maxvalue",
  "description": "Investigating Scala compiler magic, companion objects, and why duck-typing Numeric types for MaxValue fails in Scala 2.8.1.",
  "path": "/2011/02/19/scala-compiler-fictions-and-the-suprising-difficulties-asking-anyval-its-maxvalue",
  "publishedAt": "2011-02-19T00:00:00.000Z",
  "site": "at://did:plc:2ngsl5btroik454wzz7vpbzq/site.standard.publication/3mn67n3cam32w",
  "textContent": "Scala's polite compiler fictions & the surprising difficulties of asking an AnyVal it's MaxValue\n\nIn day to day programming I have found Scala allows me to make my code clearer and significantly more fun to write.\n\nYet somehow a simple code demo to get the numeric types to print their max and min values turned into a multi-man-hour-brain-teaser. \nThat's not something I want from my tools, so what follows is the highlights of the ensuing research, presented here so that Scaloids of the future may one day unearth these findings and laugh at the trifling matter that once troubled us. Some class names may have been changed, to protect the innocent, and make me laugh.\n\n> \"Hey, how do I write a method to print out the max and min value of Byte, Short, Int, Long...\"\n\n> \"hmm, that should be pretty simple, let's take a look at what you got.\"\n\nOutput\n\n> \"All good so far, but how would we write a method to get rid of all the repeated code?\"\n\n> \"hmm. Let's have a go\"\n\nRats. I'd assumed something like MaxValue would be common to all the AnyVals. Compiler says no. Let's actually find out where MaxValue is defined. And here lies the first surprising difficulty:\n\n\tInt.MaxValue does not currently appear anywhere in the ScalaDoc API.\n\nThat's weird, since it's now [the recommended way of getting that information][1]\n\nHmm, so where is MaxValue defined?\n\nWell, from first principles, when we say Int.MaxValue in Scala we are talking about a member of the Int companion object rather than a static member of the Int class as would be the case in Java.\nSo let's take a look at the docs for that:\n\t\n\tInt\n\tobject Int extends AnyValCompanion\n\tA object representing 'object scala.Int'. It should never be used directly\n\n\tValue Members\n\t\tdef toString () : String\n\t\t\tReturns a string representation of the object.\n\nhttp://www.scala-lang.org/api/current/scala/runtime/Int$.html\n\nGreat. toString and a bizzarre note that this object \"Should never be used directly\". I'm gonna put that into the pile marked \"misleading documentations I have known\", and carry on. Not that this alley gets us very far, as apparently Int.MaxValue is not a notable enough public member to warrant documenting.\nPutting the frustration back in the box, this sort of documentation mishap often boils down to refactorings and communication issues, let's see if we can't get some background on this troublesome value...\n\n\t\n\tobject Math\n\tobject Math extends MathCommon\n\tdeprecated: use scala.math package instead\n\n\tval MAX_INT : Int\n\tdeprecated: Use scala.Int.MaxValue instead\n\nhttp://www.scala-lang.org/api/current/scala/Math$.html\n\nOk, so we can see that there has been some noodling around where best to put the max value information, this would explain some of the weirdness.\nMore interestingly, Scala is your flexible friend, so what can we do about it? Let's have another go at that maxor function, this time with feeling, and maybe some thinking too.\n\nWhat do we want?\n\n- A function to takes one of Byte, Short, Int, Long and maybe even Float and Double too, as a parameter.\n- Returns unit and has the side effect of printing the largest number that numerical type can represent.\n\nObviously if this were part of a larger system, we would make a proper function that returned a String rather than causing side-effects, but right now that's the least of our troubles.\n\nSo why is this even remotely difficult?\n\nWell, we'd like to pass in a variety of AnyValCompanion objects (Int, Byte, etc) and then call a MaxValue function on that object. We know each one implements MaxValue but it isn't defined as part of the AnyValCompanion object contract.\n\nhmm...\n\n_Stand back, I am going to try duck-typing_\n\nKabooom. Hmm... that should have worked! Is this a sign from the capacitors that duck typing is evil and should be avoided? \nNo, and before you all shout at me, yes, I know this isn't really duck typing but if you find a simple way to explain what Scala is up to there, do let me know. \nI read it as \"the parameter to maxDuck can be any object that has a member called MaxValue that returns an AnyVal\", and seeing as we only want to call toString on the result of MaxValue, that seems to capture our requirements.\n\nThe MaxValue member that we are interested in has a different signature on each numeric type; Int's returns an Int, and Byte's returns a Byte. \nMore importantly MaxValue is common to all the numeric types but isn't defined on any of their common parents or traits, so we went duck style, and so maxDuck says: if it quacks like something with a MaxValue, then that's good enough for us.\nI found some other [dreadnought weight solutions][2], involving creating a type for each numeric type, but that kind of boilerplate is exactly what I came to Scala to avoid.\n\nSo let's press on. Our error appears to be telling us that there isn't a MaxValue() method defined on scala.runtime.Int$. The Int$ tells us it is trying to look it up on the companion object, but I thought we already proved in the first few lines that it does exist, even if undocumented.\nAnd so to surprising difficulty #2:\n\n\t\"The AnyVal companion classes are are added synthetically by the compiler\"\n\n[http://www.scala-lang.org/node/6650][1]\n\nI read this as, N.B. here be beasties, take care, and a sword. But then I do have a tendency to see patterns in noise. Let's see if we can prove that it's compiler voodoo at the root of all this:\n\nIt works! Ha! In your face compiler. You have been caught out in a lie, or, performing \"polite compiler fictions\" as mentioned in the wonderfully evocative Scala commit msg that ends this reign of voodoo.\n\n> root/scala/trunk/src/library/scala/Byte.scala\n>\n>Revision 24068, 5.7 KB (checked in by extempore, 4 weeks ago)\n>The AnyVal? types become source files instead of polite\n>compiler fictions.\n>\n>!! You'll need a serious \"ant all.clean\" now. !!\n>\n>As of this commit the system is fully bootstrapped and the\n>synthetic code eliminated: only the source files remain.\n>The sort-of-AnyVal?-companions in scala.runtime.* have all\n>been eliminated because the actual companions can do everything;\n>deprecated vals in the scala.runtime package object point to\n>the companions. This left AnyValCompanion? as the only AnyVal?\n>related thing in the runtime package: that made little sense,\n>so I deprecated and moved it as well.\n>\n>Starr is based on r24066 plus this commit. Closes #4121.\n>Review by rytz, odersky.\n\nhttps://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src//library/scala/Byte.scala\n\nHat's off to extempore for providing the fix, and introducing me to the phrase \"polite compiler fictions\". I for one welcome our new French speaking overlords.\n\nConclusions\n\n- Scala is ace, written by poetic wizards. \n- Compiler magic leads to nuances, nuances lead to frustration, and blog posts.\n- A function that prints the MaxValue of anything with a MaxValue can be simply expressed, but on Scala 2.8.1, it doen't work for Int, Byte and co. due to a social faux-pas by an otherwise polite compiler.\n- It has been noted and fixed by the aforementioned wizards.\n\nCredits and links\n- Thanks to Martin & Cemal for finding the issue and discussing the solutions.\n- Thanks to extempore for services to both computer and human language.\n- Thanks to @_alanshaw & @davidparry for pulling typos and patterns out of this noise.\n- http://www.scala-lang.org/node/6650\n- http://www.scala-lang.org/node/739\n- http://www.scala-lang.org/node/136\n- https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src//library/scala/Byte.scala\n- http://www.scala-lang.org/api/current/scala/runtime/Int$.html\n\n[1]: http://www.scala-lang.org/node/6650\n[2]: http://stackoverflow.com/questions/4338398/scala-how-to-make-requirements-of-the-type-parametres-of-generic-classes",
  "title": "Scala's polite compiler fictions & the surprising difficulties of asking an AnyVal it's MaxValue"
}