diff --git a/README.md b/README.md index 36a3e7b..2f92e10 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,60 @@ implicitly-yours Sample Code for Dallas Scala Enthusiasts presentation -## Building IDE files -### Eclipse +## The Slides +### TL;DR [Slides here](https://gangstead.github.io/implicitly-yours) + +Since the default branch is gh-pages, go to http://gangstead.github.io/implicitly-yours to view the slides. + +To view the slides locally start a [static http server](https://gist.github.com/willurd/5720255) from that directory. My preferred way: + +``` +# one time, to install the dependency +> npm install -g http-server + +# start the server in the base directory. -o flag opens browser +> http-server -o +``` + +## The Code +### TL;DR `sbt run` +### Running + +The sample code has multiple main classes. From the command line type `sbt run` and you will get prompted to choose one: +``` +gangstead$ sbt run +[info] Loading global plugins from /Users/gangstead/.sbt/0.13/plugins +[info] Loading project definition from /Users/gangstead/scala/implicitly-yours/project +[info] Set current project to implicitly-yours (in build file:/Users/gangstead/scala/implicitly-yours/) +[info] Compiling 3 Scala sources to /Users/gangstead/scala/implicitly-yours/target/scala-2.11/classes... +[warn] Multiple main classes detected. Run 'show discoveredMainClasses' to see the list + +Multiple main classes detected, select one to run: + +[1] gangstead.akka.main +[2] gangstead.ImplicitlyImplicit +[3] gangstead.ImplicitClassUseCase +[4] gangstead.ImplicitParams +[5] gangstead.ImplicitConversionUseCase + +Enter number: 2 +``` +If you want to make changes to the code and see compiler output in real time then use the command `sbt ~compile` + +``` +gangstead$ sbt ~compile +[info] Loading global plugins from /Users/gangstead/.sbt/0.13/plugins +[info] Loading project definition from /Users/gangstead/scala/implicitly-yours/project +[info] Set current project to implicitly-yours (in build file:/Users/gangstead/scala/implicitly-yours/) +[info] Compiling 3 Scala sources to /Users/gangstead/scala/implicitly-yours/target/scala-2.11/classes... +[success] Total time: 7 s, completed Jan 9, 2015 12:32:05 PM +1. Waiting for source changes... (press enter to interrupt) +_ +``` +Now whenever you save a file sbt will recompile and display any warnings or errors. + +### Building IDE files +#### Eclipse This project includes the plugin to generate Eclipse project files. From the console: ``` > sbt eclipse @@ -19,19 +71,5 @@ Optionally if you want to include the sources of the dependencies: ``` This will take longer in big projects, but this project is small. I don't know why you can't just do `sbt eclipse with-source=true`. That's what the plugin docs say, but it won't work for me. -### IDEA +#### IDEA Intellij IDEA can import SBT projects natively. - - -## The Slides -Since the default branch is gh-pages, go to http://gangstead.github.io/implicitly-yours to view the slides. - -To view the slides locally start a [static http server](https://gist.github.com/willurd/5720255) from that directory. My preferred way: - -``` -# one time, to install the dependency -> npm install -g http-server - -# start the server in the base directory. -o flag opens browser -> http-server -o -``` diff --git a/slides/slides.md b/slides/slides.md index 37a00c2..f490132 100644 --- a/slides/slides.md +++ b/slides/slides.md @@ -2,7 +2,8 @@ class: center, middle # implicitly yours ### Steven Gangstead -### code and slides at https://github.com/gangstead/implicitly-yours +### slides https://gangstead.github.io/implicitly-yours +### code https://github.com/gangstead/implicitly-yours @Gangstead .footnote[.round[![:scale 20%](slides/credera.jpg)]] --- @@ -145,7 +146,7 @@ implicit def toVeryEnthusiast(i : Int) = Enthusiast(i*10) - Extend classes that you can't otherwise modify - Reduce boilerplate code by having a bunch of conversions to one base class (aka [Magnet Pattern](http://spray.io/blog/2012-12-13-the-magnet-pattern/)) -- `enhancement(thing)` becomes `thing.enhancement` (just preference?) +- `enhancement(thing)` becomes `thing.enhancement` (better encapsulation) --- # Implicit Classes ~~Pimping~~ Bedazzling originally of the form diff --git a/src/main/scala/gangstead/ImplicitParams.scala b/src/main/scala/gangstead/ImplicitParams.scala index e66fa1c..377447b 100644 --- a/src/main/scala/gangstead/ImplicitParams.scala +++ b/src/main/scala/gangstead/ImplicitParams.scala @@ -6,7 +6,7 @@ object ImplicitParams { //implicit val no: Int = -1 //can only have one implicit type match! def add(x: Int)(implicit y: Int) = x + y - + //def add2(x: Int, implicit y: Int) = x + y //can't have just one param implicit def main(args: Array[String]) { println( add(5) ) // takes n from the current scope println( add(5) (1) ) //can always call explicitly diff --git a/src/main/scala/gangstead/ImplicitlyImplicit.scala b/src/main/scala/gangstead/ImplicitlyImplicit.scala index 205c2b6..c45043e 100644 --- a/src/main/scala/gangstead/ImplicitlyImplicit.scala +++ b/src/main/scala/gangstead/ImplicitlyImplicit.scala @@ -3,6 +3,7 @@ package gangstead object ImplicitlyImplicit extends App { def basic() = { + println("\nbasic") implicit val n: Int = 5 //def add(x: Int)(implicit y: Int) = x + y @@ -13,17 +14,55 @@ object ImplicitlyImplicit extends App { println(add(5)) } + /** + * From discussion in the meetup, there is a slight difference between + * using the implicit param and implicitly in the order of execution. + * The implicit parameter is evaluated when the method is called so + * if the implicit is a lazy val or a costly def the delay is incurred + * before the implicit is actually used. + */ + def cornerCase() = { + println("\ncorner case") + + implicit def n = { println("a") ; 10} + + def add(x: Int) = { + println("b") + x + implicitly[Int] + } + + def add2(x: Int)(implicit y: Int) = { + println("b") + x + y + } + + println(add(5)) //b a 15 + println(add2(5))// a b 15 + } + + /** + * If your function takes an implicit type the compiler can and will use a subtype + * It is legal to have a type and subtype in scope, the compiler will use the subtype. + * In this case we need a List[Any] and have List[Any], List[AnyVal] and List[Int] available. + * The List[Int] is a subtype of the other two. If a List[Double] were available we'd get a compiler + * error because the compiler can't choose between the two. + */ def subtypes() = { + println("\nsubtypes") //Most specific subtype whens def printList(implicit l: List[Any]) = l foreach println implicit val emptyList: List[Any] = Nil + implicit val anyValList: List[AnyVal] = List(1,2.0) implicit val intyList: List[Int] = List(1, 2, 3) + //implicit val doublyList: List[Double] = List(1.0,2.0,3.1) //ERROR. Double not a sub or parent type of Int. + printList //1 2 3 } def typeParams() = { + println("\ntypeparams") //type parameters implicitly implicit def emptyList[T]: List[T] = Nil @@ -33,8 +72,10 @@ object ImplicitlyImplicit extends App { /** * source: http://www.drmaciver.com/2008/03/an-introduction-to-implicit-arguments/ + * Advanced: Implicit def with an implicit parameter. */ def doubleImplicit() = { + println("\ndouble implicit") case class Foo[T](t: T) implicit val hello = "Hello" @@ -44,6 +85,7 @@ object ImplicitlyImplicit extends App { } basic() + cornerCase() subtypes() typeParams() doubleImplicit()