├── .bsp └── sbt.json ├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── encodings.xml ├── hydra.xml ├── misc.xml ├── modules.xml ├── modules │ ├── scala-2-advanced-build.iml │ └── scala-2-advanced.iml ├── sbt.xml ├── scala_compiler.xml ├── scala_settings.xml └── vcs.xml ├── README.md ├── build.sbt ├── project ├── build.properties ├── project │ └── target │ │ └── config-classes │ │ └── $41de159e78a080d879ac.cache └── target │ ├── config-classes │ ├── $2f0d6020feb87165a227.cache │ ├── $ace5525ffd90805a6f8e.cache │ └── $e46239a10b23e237b883.cache │ ├── scala-2.12 │ └── sbt-1.0 │ │ ├── sync │ │ └── copy-resource │ │ └── update │ │ └── update_cache_2.12 │ │ ├── inputs │ │ └── output │ └── streams │ ├── _global │ ├── _global │ │ ├── _global │ │ │ └── streams │ │ │ │ └── out │ │ └── csrLogger │ │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── csrConfiguration │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── csrProject │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── dependencyPositions │ │ └── _global │ │ │ └── streams │ │ │ └── update_cache_2.12 │ │ │ ├── input_dsp │ │ │ └── output_dsp │ ├── ivyConfiguration │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── ivySbt │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── moduleSettings │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── projectDescriptors │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── scalaCompilerBridgeScope │ │ └── _global │ │ │ └── streams │ │ │ └── out │ └── update │ │ └── _global │ │ └── streams │ │ └── out │ ├── compile │ ├── _global │ │ └── _global │ │ │ ├── compileOutputs │ │ │ └── previous │ │ │ └── discoveredMainClasses │ │ │ └── data │ ├── bspReporter │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── compile │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── compileIncremental │ │ └── _global │ │ │ └── streams │ │ │ ├── export │ │ │ └── out │ ├── copyResources │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── dependencyClasspath │ │ └── _global │ │ │ └── streams │ │ │ └── export │ ├── exportedProducts │ │ └── _global │ │ │ └── streams │ │ │ └── export │ ├── externalDependencyClasspath │ │ └── _global │ │ │ └── streams │ │ │ └── export │ ├── incOptions │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── internalDependencyClasspath │ │ └── _global │ │ │ └── streams │ │ │ ├── export │ │ │ └── out │ ├── managedClasspath │ │ └── _global │ │ │ └── streams │ │ │ └── export │ ├── scalacOptions │ │ └── _global │ │ │ └── streams │ │ │ └── out │ ├── unmanagedClasspath │ │ └── _global │ │ │ └── streams │ │ │ ├── export │ │ │ └── out │ └── unmanagedJars │ │ └── _global │ │ └── streams │ │ └── export │ └── runtime │ ├── dependencyClasspath │ └── _global │ │ └── streams │ │ └── export │ ├── exportedProducts │ └── _global │ │ └── streams │ │ └── export │ ├── externalDependencyClasspath │ └── _global │ │ └── streams │ │ └── export │ ├── fullClasspath │ └── _global │ │ └── streams │ │ └── export │ ├── internalDependencyClasspath │ └── _global │ │ └── streams │ │ ├── export │ │ └── out │ ├── managedClasspath │ └── _global │ │ └── streams │ │ └── export │ ├── unmanagedClasspath │ └── _global │ │ └── streams │ │ ├── export │ │ └── out │ └── unmanagedJars │ └── _global │ └── streams │ └── export ├── src ├── .DS_Store ├── exercises │ ├── EqualityPlayground.scala │ ├── MySet.scala │ └── StreamsPlayground.scala ├── lectures │ ├── part1as │ │ ├── AdvancedPatternMatching.scala │ │ ├── DarkSugars.scala │ │ └── Recap.scala │ ├── part2afp │ │ ├── CurriesPAF.scala │ │ ├── LazyEvaluation.scala │ │ ├── Monads.scala │ │ └── PartialFunctions.scala │ ├── part3concurrency │ │ ├── FuturesPromises.scala │ │ ├── Intro.scala │ │ ├── ParallelUtils.scala │ │ └── ThreadCommunication.scala │ ├── part4implicits │ │ ├── ImplicitsIntro.scala │ │ ├── JSONSerialization.scala │ │ ├── MagnetPattern.scala │ │ ├── MyTypeClassTemplate.scala │ │ ├── OrganizingImplicits.scala │ │ ├── PimpMyLibrary.scala │ │ ├── ScalaJavaConversions.scala │ │ └── TypeClasses.scala │ └── part5ts │ │ ├── FBoundedPolymorphism.scala │ │ ├── HigherKindedTypes.scala │ │ ├── PathDependentTypes.scala │ │ ├── Reflection.scala │ │ ├── RockingInheritance.scala │ │ ├── SelfTypes.scala │ │ ├── StructuralTypes.scala │ │ ├── TypeMembers.scala │ │ └── Variance.scala └── playground │ ├── JavaPlayground.java │ └── ScalaPlayground.scala └── target ├── .history3 ├── scala-2.13 └── update │ └── update_cache_2.13 │ ├── inputs │ └── output └── streams ├── _global ├── _global │ ├── csrLogger │ │ └── _global │ │ │ └── streams │ │ │ └── out │ └── dumpStructure │ │ └── _global │ │ └── streams │ │ └── out ├── csrConfiguration │ └── _global │ │ └── streams │ │ └── out ├── csrProject │ └── _global │ │ └── streams │ │ └── out ├── dependencyPositions │ └── _global │ │ └── streams │ │ └── update_cache_2.13 │ │ ├── input_dsp │ │ └── output_dsp ├── ivyConfiguration │ └── _global │ │ └── streams │ │ └── out ├── ivySbt │ └── _global │ │ └── streams │ │ └── out ├── moduleSettings │ └── _global │ │ └── streams │ │ └── out ├── projectDescriptors │ └── _global │ │ └── streams │ │ └── out ├── ssExtractDependencies │ └── _global │ │ └── streams │ │ └── out ├── update │ └── _global │ │ └── streams │ │ └── out └── updateClassifiers │ └── _global │ └── streams │ ├── out │ └── update_cache_2.13 │ ├── inputs │ └── output ├── compile ├── externalDependencyClasspath │ └── _global │ │ └── streams │ │ └── export ├── managedClasspath │ └── _global │ │ └── streams │ │ └── export ├── scalacOptions │ └── _global │ │ └── streams │ │ └── out ├── unmanagedClasspath │ └── _global │ │ └── streams │ │ ├── export │ │ └── out └── unmanagedJars │ └── _global │ └── streams │ └── export ├── runtime ├── externalDependencyClasspath │ └── _global │ │ └── streams │ │ └── export ├── managedClasspath │ └── _global │ │ └── streams │ │ └── export ├── unmanagedClasspath │ └── _global │ │ └── streams │ │ ├── export │ │ └── out └── unmanagedJars │ └── _global │ └── streams │ └── export └── test ├── externalDependencyClasspath └── _global │ └── streams │ └── export ├── managedClasspath └── _global │ └── streams │ └── export ├── unmanagedClasspath └── _global │ └── streams │ ├── export │ └── out └── unmanagedJars └── _global └── streams └── export /.bsp/sbt.json: -------------------------------------------------------------------------------- 1 | {"name":"sbt","version":"1.8.0","bspVersion":"2.1.0-M1","languages":["scala"],"argv":["/Applications/IntelliJ IDEA CE.app/Contents/jbr/Contents/Home/bin/java","-Xms100m","-Xmx100m","-classpath","/Users/daniel/Library/Application Support/JetBrains/IdeaIC2023.1/plugins/Scala/launcher/sbt-launch.jar","-Dsbt.script=/usr/local/bin/sbt","xsbt.boot.Boot","-bsp"]} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/scala,intellij 3 | 4 | ### Intellij ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff 9 | .idea/**/workspace.xml 10 | .idea/**/tasks.xml 11 | .idea/**/usage.statistics.xml 12 | .idea/**/dictionaries 13 | .idea/**/shelf 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/modules.xml 36 | # .idea/*.iml 37 | # .idea/modules 38 | 39 | # CMake 40 | cmake-build-*/ 41 | 42 | # Mongo Explorer plugin 43 | .idea/**/mongoSettings.xml 44 | 45 | # File-based project format 46 | *.iws 47 | 48 | # IntelliJ 49 | out/ 50 | 51 | # mpeltonen/sbt-idea plugin 52 | .idea_modules/ 53 | 54 | # JIRA plugin 55 | atlassian-ide-plugin.xml 56 | 57 | # Cursive Clojure plugin 58 | .idea/replstate.xml 59 | 60 | # Crashlytics plugin (for Android Studio and IntelliJ) 61 | com_crashlytics_export_strings.xml 62 | crashlytics.properties 63 | crashlytics-build.properties 64 | fabric.properties 65 | 66 | # Editor-based Rest Client 67 | .idea/httpRequests 68 | 69 | ### Intellij Patch ### 70 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 71 | 72 | # *.iml 73 | # modules.xml 74 | # .idea/misc.xml 75 | # *.ipr 76 | 77 | # Sonarlint plugin 78 | .idea/sonarlint 79 | 80 | ### Scala ### 81 | *.class 82 | *.log 83 | 84 | 85 | # End of https://www.gitignore.io/api/scala,intellij 86 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/hydra.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules/scala-2-advanced-build.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 115 | -------------------------------------------------------------------------------- /.idea/modules/scala-2-advanced.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/sbt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/scala_compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/scala_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## The official repository for the Scala Advanced course 2 | 3 | **For the new course repo (Scala 3), use this link: https://github.com/rockthejvm/advanced-scala**. The new course is at https://rockthejvm.com/p/advanced-scala. 4 | 5 | Powered by [Rock the JVM!](rockthejvm.com) 6 | 7 | This repository contains the code we wrote during [Rock the JVM's Scala 2 Advanced course](https://rockthejvm.com/course/scala-2-advanced) on Udemy. Unless explicitly mentioned, the code in this repository is exactly what was caught on camera. 8 | 9 | How to install: 10 | - either clone the repo or download as zip 11 | - open with IntelliJ as it's a simple IDEA project 12 | 13 | If you have changes to suggest to this repo, either 14 | - submit a GitHub issue 15 | - tell me in the course Q/A forum 16 | - submit a pull request! 17 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | 2 | lazy val root = project 3 | .in(file(".")) 4 | .settings( 5 | name := "scala-2-advanced", 6 | version := "0.1.0", 7 | scalaVersion := "2.13.5", 8 | libraryDependencies ++= Seq( 9 | "com.novocode" % "junit-interface" % "0.11" % "test", 10 | "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4", 11 | ) 12 | ) 13 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.8.0 2 | -------------------------------------------------------------------------------- /project/project/target/config-classes/$41de159e78a080d879ac.cache: -------------------------------------------------------------------------------- 1 | sbt.internal.DslEntry -------------------------------------------------------------------------------- /project/target/config-classes/$2f0d6020feb87165a227.cache: -------------------------------------------------------------------------------- 1 | root 2 | -------------------------------------------------------------------------------- /project/target/config-classes/$ace5525ffd90805a6f8e.cache: -------------------------------------------------------------------------------- 1 | sbt.internal.DslEntry -------------------------------------------------------------------------------- /project/target/config-classes/$e46239a10b23e237b883.cache: -------------------------------------------------------------------------------- 1 | sbt.internal.DslEntry -------------------------------------------------------------------------------- /project/target/scala-2.12/sbt-1.0/sync/copy-resource: -------------------------------------------------------------------------------- 1 | [[{},{}],{}] -------------------------------------------------------------------------------- /project/target/scala-2.12/sbt-1.0/update/update_cache_2.12/inputs: -------------------------------------------------------------------------------- 1 | -1885806411 -------------------------------------------------------------------------------- /project/target/streams/_global/_global/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/_global/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/_global/csrLogger/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/_global/csrLogger/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/csrConfiguration/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/csrConfiguration/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/csrProject/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/csrProject/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/dependencyPositions/_global/streams/update_cache_2.12/input_dsp: -------------------------------------------------------------------------------- 1 | 116610538 -------------------------------------------------------------------------------- /project/target/streams/_global/dependencyPositions/_global/streams/update_cache_2.12/output_dsp: -------------------------------------------------------------------------------- 1 | {"{\"organization\":\"org.scala-lang\",\"name\":\"scala-library\",\"revision\":\"2.12.17\",\"configurations\":\"provided\",\"isChanging\":false,\"isTransitive\":true,\"isForce\":false,\"explicitArtifacts\":[],\"inclusions\":[],\"exclusions\":[],\"extraAttributes\":{},\"crossVersion\":{\"type\":\"Disabled\"}}":{"value":{"$fields":["path","range"],"path":"/private/var/folders/0_/l801qy2501d6655txswpw8lc0000gn/T/idea.sbt","range":{"$fields":["start","end"],"start":5,"end":11}},"type":"RangePosition"},"{\"organization\":\"org.jetbrains.scala\",\"name\":\"sbt-structure-extractor\",\"revision\":\"2022.3.1\",\"isChanging\":false,\"isTransitive\":true,\"isForce\":false,\"explicitArtifacts\":[],\"inclusions\":[],\"exclusions\":[],\"extraAttributes\":{\"e:sbtVersion\":\"1.0\",\"e:scalaVersion\":\"2.12\"},\"crossVersion\":{\"type\":\"Disabled\"}}":{"value":{"$fields":["path","range"],"path":"/private/var/folders/0_/l801qy2501d6655txswpw8lc0000gn/T/idea.sbt","range":{"$fields":["start","end"],"start":5,"end":11}},"type":"RangePosition"},"{\"organization\":\"org.jetbrains.scala\",\"name\":\"sbt-idea-shell\",\"revision\":\"2021.1.0\",\"isChanging\":false,\"isTransitive\":true,\"isForce\":false,\"explicitArtifacts\":[],\"inclusions\":[],\"exclusions\":[],\"extraAttributes\":{\"e:sbtVersion\":\"1.0\",\"e:scalaVersion\":\"2.12\"},\"crossVersion\":{\"type\":\"Disabled\"}}":{"value":{"$fields":["path","range"],"path":"/private/var/folders/0_/l801qy2501d6655txswpw8lc0000gn/T/idea.sbt","range":{"$fields":["start","end"],"start":5,"end":11}},"type":"RangePosition"},"{\"organization\":\"org.jetbrains.scala\",\"name\":\"sbt-idea-compiler-indices\",\"revision\":\"1.0.13\",\"isChanging\":false,\"isTransitive\":true,\"isForce\":false,\"explicitArtifacts\":[],\"inclusions\":[],\"exclusions\":[],\"extraAttributes\":{\"e:sbtVersion\":\"1.0\",\"e:scalaVersion\":\"2.12\"},\"crossVersion\":{\"type\":\"Disabled\"}}":{"value":{"$fields":["path","range"],"path":"/private/var/folders/0_/l801qy2501d6655txswpw8lc0000gn/T/idea.sbt","range":{"$fields":["start","end"],"start":5,"end":11}},"type":"RangePosition"}} -------------------------------------------------------------------------------- /project/target/streams/_global/ivyConfiguration/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/ivyConfiguration/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/ivySbt/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/ivySbt/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/moduleSettings/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/moduleSettings/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/projectDescriptors/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/projectDescriptors/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/scalaCompilerBridgeScope/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/_global/scalaCompilerBridgeScope/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/_global/update/_global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] not up to date. inChanged = true, force = false 2 | [debug] Updating ProjectRef(uri("file:/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/"), "scala-2-advanced-build")... 3 | [warn] Unrecognized repository Scala Plugin Bundled Repository, ignoring it 4 | [warn] Unrecognized repository Scala Plugin Bundled Repository, ignoring it 5 | [debug] Done updating ProjectRef(uri("file:/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/"), "scala-2-advanced-build") 6 | -------------------------------------------------------------------------------- /project/target/streams/compile/_global/_global/compileOutputs/previous: -------------------------------------------------------------------------------- 1 | ["sbt.Task[scala.collection.Seq[java.nio.file.Path]]",["/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/zinc/inc_compile_2.12.zip"]] -------------------------------------------------------------------------------- /project/target/streams/compile/_global/_global/discoveredMainClasses/data: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /project/target/streams/compile/bspReporter/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/compile/bspReporter/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/compile/compile/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/compile/compile/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/compile/compileIncremental/_global/streams/export: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/compile/compileIncremental/_global/streams/export -------------------------------------------------------------------------------- /project/target/streams/compile/compileIncremental/_global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] [zinc] IncrementalCompile ----------- 2 | [debug] IncrementalCompile.incrementalCompile 3 | [debug] previous = Stamps for: 0 products, 0 sources, 0 libraries 4 | [debug] current source = Set() 5 | [debug] > initialChanges = InitialChanges(Changes(added = Set(), removed = Set(), changed = Set(), unmodified = ...),Set(),Set(),API Changes: Set()) 6 | [debug] Full compilation, no sources in previous analysis. 7 | -------------------------------------------------------------------------------- /project/target/streams/compile/copyResources/_global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] Copy resource mappings:  2 | [debug]   3 | -------------------------------------------------------------------------------- /project/target/streams/compile/dependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/.sbt/1.0/plugins/target/scala-2.12/sbt-1.0/classes:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-library.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-shell_2.12_1.0/2021.1.0/sbt-idea-shell-2021.1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-compiler-indices_2.12_1.0/1.0.13/sbt-idea-compiler-indices-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/scala-compiler-indices-protocol_2.12/1.0.13/scala-compiler-indices-protocol_2.12-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.12/1.3.5/spray-json_2.12-1.3.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-compiler.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-reflect.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/lm-coursier-shaded_2.12-2.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classfile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-ivy_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/testing_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-cache_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-jawn-parser_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/task-system_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-position_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-reader-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-api-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbt-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbinary_2.12-0.5.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/error_prone_annotations-2.4.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-core_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/config-1.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-interface-1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-relation_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/slf4j-api-2.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-tracking_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-core_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/file-tree-views-2.1.9.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-bridge_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-apache-http_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/checker-qual-3.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/caffeine-2.8.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/completion_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-compiler-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-core-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-apiinfo_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-slf4j-impl-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-2.14.7-sbt-a1b0ffbb8f64bb820f4f84a0c07a0c0964507493.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jna-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ssl-config-core_2.12-0.6.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-agent-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-lm-integration_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-reflect-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/launcher-interface-1.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-logging_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jansi-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/run_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-parser-combinators_2.12-1.1.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ipcsocket-1.5.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/protocol_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/reactive-streams-1.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jansi-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/disruptor-3.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-builtins-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-library-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-murmurhash_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/template-resolver-0.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classpath_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/io_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-scalajson_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jsch-0.1.54.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-style-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/logic_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-platform-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-collection-compat_2.12-2.8.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist-core-assembly-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/collections_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scripted-plugin_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ivy-2.3.0-sbt-a8f9eb5bf09d0539ea3658a2c2d4e09755b5133e.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/tasks_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zero-allocation-hashing-0.10.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/command_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main-settings_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/actions_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-scalajson_2.12-1.0.0-M4.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/core-macros_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-apache-httpasyncclient-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-control_2.12-1.8.0.jar 2 | -------------------------------------------------------------------------------- /project/target/streams/compile/exportedProducts/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/classes 2 | -------------------------------------------------------------------------------- /project/target/streams/compile/externalDependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-library.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-shell_2.12_1.0/2021.1.0/sbt-idea-shell-2021.1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-compiler-indices_2.12_1.0/1.0.13/sbt-idea-compiler-indices-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/scala-compiler-indices-protocol_2.12/1.0.13/scala-compiler-indices-protocol_2.12-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.12/1.3.5/spray-json_2.12-1.3.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-compiler.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-reflect.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/lm-coursier-shaded_2.12-2.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classfile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-ivy_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/testing_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-cache_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-jawn-parser_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/task-system_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-position_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-reader-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-api-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbt-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbinary_2.12-0.5.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/error_prone_annotations-2.4.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-core_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/config-1.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-interface-1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-relation_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/slf4j-api-2.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-tracking_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-core_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/file-tree-views-2.1.9.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-bridge_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-apache-http_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/checker-qual-3.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/caffeine-2.8.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/completion_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-compiler-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-core-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-apiinfo_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-slf4j-impl-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-2.14.7-sbt-a1b0ffbb8f64bb820f4f84a0c07a0c0964507493.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jna-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ssl-config-core_2.12-0.6.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-agent-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-lm-integration_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-reflect-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/launcher-interface-1.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-logging_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jansi-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/run_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-parser-combinators_2.12-1.1.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ipcsocket-1.5.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/protocol_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/reactive-streams-1.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jansi-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/disruptor-3.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-builtins-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-library-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-murmurhash_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/template-resolver-0.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classpath_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/io_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-scalajson_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jsch-0.1.54.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-style-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/logic_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-platform-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-collection-compat_2.12-2.8.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist-core-assembly-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/collections_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scripted-plugin_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ivy-2.3.0-sbt-a8f9eb5bf09d0539ea3658a2c2d4e09755b5133e.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/tasks_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zero-allocation-hashing-0.10.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/command_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main-settings_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/actions_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-scalajson_2.12-1.0.0-M4.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/core-macros_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-apache-httpasyncclient-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-control_2.12-1.8.0.jar 2 | -------------------------------------------------------------------------------- /project/target/streams/compile/incOptions/_global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] Created transactional ClassFileManager with tempDir = /Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/classes.bak 2 | [debug] Removing the temporary directory used for backing up class files: /Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/classes.bak 3 | -------------------------------------------------------------------------------- /project/target/streams/compile/internalDependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /project/target/streams/compile/internalDependencyClasspath/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/compile/internalDependencyClasspath/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/compile/managedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-library.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-shell_2.12_1.0/2021.1.0/sbt-idea-shell-2021.1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-compiler-indices_2.12_1.0/1.0.13/sbt-idea-compiler-indices-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/scala-compiler-indices-protocol_2.12/1.0.13/scala-compiler-indices-protocol_2.12-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.12/1.3.5/spray-json_2.12-1.3.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-compiler.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-reflect.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/lm-coursier-shaded_2.12-2.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classfile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-ivy_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/testing_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-cache_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-jawn-parser_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/task-system_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-position_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-reader-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-api-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbt-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbinary_2.12-0.5.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/error_prone_annotations-2.4.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-core_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/config-1.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-interface-1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-relation_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/slf4j-api-2.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-tracking_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-core_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/file-tree-views-2.1.9.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-bridge_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-apache-http_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/checker-qual-3.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/caffeine-2.8.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/completion_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-compiler-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-core-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-apiinfo_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-slf4j-impl-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-2.14.7-sbt-a1b0ffbb8f64bb820f4f84a0c07a0c0964507493.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jna-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ssl-config-core_2.12-0.6.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-agent-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-lm-integration_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-reflect-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/launcher-interface-1.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-logging_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jansi-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/run_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-parser-combinators_2.12-1.1.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ipcsocket-1.5.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/protocol_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/reactive-streams-1.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jansi-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/disruptor-3.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-builtins-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-library-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-murmurhash_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/template-resolver-0.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classpath_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/io_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-scalajson_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jsch-0.1.54.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-style-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/logic_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-platform-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-collection-compat_2.12-2.8.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist-core-assembly-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/collections_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scripted-plugin_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ivy-2.3.0-sbt-a8f9eb5bf09d0539ea3658a2c2d4e09755b5133e.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/tasks_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zero-allocation-hashing-0.10.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/command_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main-settings_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/actions_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-scalajson_2.12-1.0.0-M4.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/core-macros_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-apache-httpasyncclient-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-control_2.12-1.8.0.jar 2 | -------------------------------------------------------------------------------- /project/target/streams/compile/scalacOptions/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/compile/scalacOptions/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/compile/unmanagedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /project/target/streams/compile/unmanagedClasspath/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/compile/unmanagedClasspath/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/compile/unmanagedJars/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/dependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/classes:/Users/daniel/.sbt/1.0/plugins/target/scala-2.12/sbt-1.0/classes:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-shell_2.12_1.0/2021.1.0/sbt-idea-shell-2021.1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-compiler-indices_2.12_1.0/1.0.13/sbt-idea-compiler-indices-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/scala-compiler-indices-protocol_2.12/1.0.13/scala-compiler-indices-protocol_2.12-1.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-library.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.12/1.3.5/spray-json_2.12-1.3.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-compiler.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-reflect.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/lm-coursier-shaded_2.12-2.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classfile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-ivy_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/testing_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-cache_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-jawn-parser_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/task-system_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-position_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-reader-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-api-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbt-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbinary_2.12-0.5.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/error_prone_annotations-2.4.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-core_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/config-1.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-interface-1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-relation_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/slf4j-api-2.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-tracking_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-core_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/file-tree-views-2.1.9.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-bridge_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-apache-http_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/checker-qual-3.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/caffeine-2.8.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/completion_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-compiler-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-core-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-apiinfo_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-slf4j-impl-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-2.14.7-sbt-a1b0ffbb8f64bb820f4f84a0c07a0c0964507493.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jna-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ssl-config-core_2.12-0.6.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-agent-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-lm-integration_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-reflect-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/launcher-interface-1.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-logging_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jansi-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/run_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-parser-combinators_2.12-1.1.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ipcsocket-1.5.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/protocol_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/reactive-streams-1.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jansi-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/disruptor-3.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-builtins-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-library-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-murmurhash_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/template-resolver-0.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classpath_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/io_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-scalajson_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jsch-0.1.54.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-style-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/logic_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-platform-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-collection-compat_2.12-2.8.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist-core-assembly-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/collections_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scripted-plugin_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ivy-2.3.0-sbt-a8f9eb5bf09d0539ea3658a2c2d4e09755b5133e.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/tasks_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zero-allocation-hashing-0.10.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/command_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main-settings_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/actions_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-scalajson_2.12-1.0.0-M4.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/core-macros_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-apache-httpasyncclient-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-control_2.12-1.8.0.jar 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/exportedProducts/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/classes 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/externalDependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-shell_2.12_1.0/2021.1.0/sbt-idea-shell-2021.1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-compiler-indices_2.12_1.0/1.0.13/sbt-idea-compiler-indices-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/scala-compiler-indices-protocol_2.12/1.0.13/scala-compiler-indices-protocol_2.12-1.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-library.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.12/1.3.5/spray-json_2.12-1.3.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-compiler.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-reflect.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/lm-coursier-shaded_2.12-2.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classfile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-ivy_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/testing_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-cache_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-jawn-parser_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/task-system_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-position_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-reader-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-api-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbt-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbinary_2.12-0.5.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/error_prone_annotations-2.4.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-core_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/config-1.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-interface-1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-relation_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/slf4j-api-2.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-tracking_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-core_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/file-tree-views-2.1.9.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-bridge_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-apache-http_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/checker-qual-3.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/caffeine-2.8.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/completion_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-compiler-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-core-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-apiinfo_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-slf4j-impl-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-2.14.7-sbt-a1b0ffbb8f64bb820f4f84a0c07a0c0964507493.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jna-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ssl-config-core_2.12-0.6.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-agent-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-lm-integration_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-reflect-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/launcher-interface-1.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-logging_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jansi-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/run_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-parser-combinators_2.12-1.1.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ipcsocket-1.5.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/protocol_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/reactive-streams-1.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jansi-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/disruptor-3.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-builtins-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-library-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-murmurhash_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/template-resolver-0.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classpath_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/io_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-scalajson_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jsch-0.1.54.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-style-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/logic_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-platform-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-collection-compat_2.12-2.8.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist-core-assembly-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/collections_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scripted-plugin_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ivy-2.3.0-sbt-a8f9eb5bf09d0539ea3658a2c2d4e09755b5133e.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/tasks_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zero-allocation-hashing-0.10.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/command_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main-settings_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/actions_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-scalajson_2.12-1.0.0-M4.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/core-macros_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-apache-httpasyncclient-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-control_2.12-1.8.0.jar 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/fullClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/classes:/Users/daniel/.sbt/1.0/plugins/target/scala-2.12/sbt-1.0/classes:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-shell_2.12_1.0/2021.1.0/sbt-idea-shell-2021.1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-compiler-indices_2.12_1.0/1.0.13/sbt-idea-compiler-indices-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/scala-compiler-indices-protocol_2.12/1.0.13/scala-compiler-indices-protocol_2.12-1.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-library.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.12/1.3.5/spray-json_2.12-1.3.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-compiler.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-reflect.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/lm-coursier-shaded_2.12-2.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classfile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-ivy_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/testing_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-cache_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-jawn-parser_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/task-system_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-position_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-reader-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-api-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbt-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbinary_2.12-0.5.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/error_prone_annotations-2.4.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-core_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/config-1.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-interface-1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-relation_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/slf4j-api-2.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-tracking_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-core_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/file-tree-views-2.1.9.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-bridge_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-apache-http_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/checker-qual-3.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/caffeine-2.8.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/completion_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-compiler-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-core-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-apiinfo_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-slf4j-impl-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-2.14.7-sbt-a1b0ffbb8f64bb820f4f84a0c07a0c0964507493.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jna-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ssl-config-core_2.12-0.6.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-agent-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-lm-integration_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-reflect-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/launcher-interface-1.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-logging_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jansi-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/run_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-parser-combinators_2.12-1.1.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ipcsocket-1.5.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/protocol_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/reactive-streams-1.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jansi-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/disruptor-3.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-builtins-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-library-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-murmurhash_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/template-resolver-0.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classpath_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/io_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-scalajson_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jsch-0.1.54.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-style-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/logic_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-platform-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-collection-compat_2.12-2.8.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist-core-assembly-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/collections_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scripted-plugin_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ivy-2.3.0-sbt-a8f9eb5bf09d0539ea3658a2c2d4e09755b5133e.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/tasks_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zero-allocation-hashing-0.10.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/command_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main-settings_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/actions_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-scalajson_2.12-1.0.0-M4.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/core-macros_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-apache-httpasyncclient-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-control_2.12-1.8.0.jar 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/internalDependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/dev/rockthejvm/courses/scala-2-advanced/project/target/scala-2.12/sbt-1.0/classes 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/internalDependencyClasspath/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/runtime/internalDependencyClasspath/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/runtime/managedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-shell_2.12_1.0/2021.1.0/sbt-idea-shell-2021.1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/sbt-idea-compiler-indices_2.12_1.0/1.0.13/sbt-idea-compiler-indices-1.0.13.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/jetbrains/scala/scala-compiler-indices-protocol_2.12/1.0.13/scala-compiler-indices-protocol_2.12-1.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-library.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.12/1.3.5/spray-json_2.12-1.3.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-compiler.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-reflect.jar:/Users/daniel/.sbt/boot/scala-2.12.17/lib/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/lm-coursier-shaded_2.12-2.0.13.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classfile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-ivy_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/testing_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-cache_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-jawn-parser_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/task-system_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/librarymanagement-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-position_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-reader-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-api-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbt-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sbinary_2.12-0.5.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/error_prone_annotations-2.4.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-core_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/config-1.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-interface-1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-relation_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/slf4j-api-2.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-tracking_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-core_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/file-tree-views-2.1.9.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-bridge_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/gigahorse-apache-http_2.12-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/checker-qual-3.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/caffeine-2.8.5.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/completion_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-compiler-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-core-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-apiinfo_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/log4j-slf4j-impl-2.17.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-2.14.7-sbt-a1b0ffbb8f64bb820f4f84a0c07a0c0964507493.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jna-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ssl-config-core_2.12-0.6.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-compile-core_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/test-agent-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-lm-integration_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-reflect-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/launcher-interface-1.4.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-logging_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-terminal-jansi-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/run_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-parser-combinators_2.12-1.1.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ipcsocket-1.5.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/protocol_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/reactive-streams-1.0.3.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/compiler-interface-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jansi-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/disruptor-3.4.2.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-builtins-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-library-2.12.17.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-murmurhash_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/template-resolver-0.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-classpath_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/io_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/sjson-new-scalajson_2.12-0.9.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jsch-0.1.54.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-xml_2.12-2.1.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jline-style-3.19.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/logic_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/jna-platform-5.12.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scala-collection-compat_2.12-2.8.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zinc-persist-core-assembly-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/collections_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/scripted-plugin_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/ivy-2.3.0-sbt-a8f9eb5bf09d0539ea3658a2c2d4e09755b5133e.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/tasks_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/zero-allocation-hashing-0.10.1.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/command_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/main-settings_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/actions_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-scalajson_2.12-1.0.0-M4.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/core-macros_2.12-1.8.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/shaded-apache-httpasyncclient-0.7.0.jar:/Users/daniel/.sbt/boot/scala-2.12.17/org.scala-sbt/sbt/1.8.0/util-control_2.12-1.8.0.jar 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/unmanagedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /project/target/streams/runtime/unmanagedClasspath/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/project/target/streams/runtime/unmanagedClasspath/_global/streams/out -------------------------------------------------------------------------------- /project/target/streams/runtime/unmanagedJars/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/src/.DS_Store -------------------------------------------------------------------------------- /src/exercises/EqualityPlayground.scala: -------------------------------------------------------------------------------- 1 | package exercises 2 | 3 | import lectures.part4implicits.TypeClasses.User 4 | 5 | /** 6 | * Created by Daniel. 7 | */ 8 | object EqualityPlayground extends App { 9 | 10 | /** 11 | * Equality 12 | */ 13 | trait Equal[T] { 14 | def apply(a: T, b: T): Boolean 15 | } 16 | 17 | implicit object NameEquality extends Equal[User] { 18 | override def apply(a: User, b: User): Boolean = a.name == b.name 19 | } 20 | 21 | object FullEquality extends Equal[User] { 22 | override def apply(a: User, b: User): Boolean = a.name == b.name && a.email == b.email 23 | } 24 | 25 | /* 26 | Exercise: implement the TC pattern for the Equality tc. 27 | */ 28 | object Equal { 29 | def apply[T](a: T, b: T)(implicit equalizer: Equal[T]): Boolean = 30 | equalizer.apply(a, b) 31 | } 32 | 33 | val john = User("John", 32, "john@rockthejvm.com") 34 | val anotherJohn = User("John", 45, "anotherJohn@rtjvm.com") 35 | println(Equal(john, anotherJohn)) 36 | // AD-HOC polymorphism 37 | 38 | /* 39 | Exercise - improve the Equal TC with an implicit conversion class 40 | ===(anotherValue: T) 41 | !==(anotherValue: T) 42 | */ 43 | implicit class TypeSafeEqual[T](value: T) { 44 | def ===(other: T)(implicit equalizer: Equal[T]): Boolean = equalizer.apply(value, other) 45 | def !==(other: T)(implicit equalizer: Equal[T]): Boolean = ! equalizer.apply(value, other) 46 | } 47 | 48 | println(john === anotherJohn) 49 | /* 50 | john.===(anotherJohn) 51 | new TypeSafeEqual[User](john).===(anotherJohn) 52 | new TypeSafeEqual[User](john).===(anotherJohn)(NameEquality) 53 | */ 54 | /* 55 | TYPE SAFE 56 | */ 57 | println(john == 43) 58 | // println(john === 43) // TYPE SAFE 59 | } 60 | -------------------------------------------------------------------------------- /src/exercises/MySet.scala: -------------------------------------------------------------------------------- 1 | package exercises 2 | 3 | import scala.annotation.tailrec 4 | 5 | /** 6 | * Created by Daniel. 7 | */ 8 | trait MySet[A] extends (A => Boolean) { 9 | 10 | /* 11 | EXERCISE - implement a functional set 12 | */ 13 | def apply(elem: A): Boolean = 14 | contains(elem) 15 | 16 | def contains(elem: A): Boolean 17 | def +(elem: A): MySet[A] 18 | def ++(anotherSet: MySet[A]): MySet[A] // union 19 | 20 | def map[B](f: A => B): MySet[B] 21 | def flatMap[B](f: A => MySet[B]): MySet[B] 22 | def filter(predicate: A => Boolean): MySet[A] 23 | def foreach(f: A => Unit): Unit 24 | 25 | /* 26 | EXERCISE #2 27 | - removing an element 28 | - intersection with another set 29 | - difference with another set 30 | */ 31 | def -(elem: A): MySet[A] 32 | def --(anotherSet: MySet[A]): MySet[A] // difference 33 | def &(anotherSet: MySet[A]): MySet[A] // intersection 34 | 35 | // EXERCISE #3 - implement a unary_! = NEGATION of a set 36 | // set[1,2,3] => 37 | def unary_! : MySet[A] 38 | } 39 | 40 | class EmptySet[A] extends MySet[A] { 41 | def contains(elem: A): Boolean = false 42 | def +(elem: A): MySet[A] = new NonEmptySet[A](elem, this) 43 | def ++(anotherSet: MySet[A]): MySet[A] = anotherSet 44 | 45 | def map[B](f: A => B): MySet[B] = new EmptySet[B] 46 | def flatMap[B](f: A => MySet[B]): MySet[B] = new EmptySet[B] 47 | def filter(predicate: A => Boolean): MySet[A] = this 48 | def foreach(f: A => Unit): Unit = () 49 | 50 | // part 2 51 | def -(elem: A): MySet[A] = this 52 | def --(anotherSet: MySet[A]): MySet[A] = this 53 | def &(anotherSet: MySet[A]): MySet[A] = this 54 | 55 | def unary_! : MySet[A] = new PropertyBasedSet[A](_ => true) 56 | } 57 | 58 | // all elements of type A which satisfy a property 59 | // { x in A | property(x) } 60 | class PropertyBasedSet[A](property: A => Boolean) extends MySet[A] { 61 | def contains(elem: A): Boolean = property(elem) 62 | // { x in A | property(x) } + element = { x in A | property(x) || x == element } 63 | def +(elem: A): MySet[A] = 64 | new PropertyBasedSet[A](x => property(x) || x == elem) 65 | 66 | // { x in A | property(x) } ++ set => { x in A | property(x) || set contains x } 67 | def ++(anotherSet: MySet[A]): MySet[A] = 68 | new PropertyBasedSet[A](x => property(x) || anotherSet(x)) 69 | 70 | // all integers => (_ % 3) => [0 1 2] 71 | def map[B](f: A => B): MySet[B] = politelyFail 72 | def flatMap[B](f: A => MySet[B]): MySet[B] = politelyFail 73 | def foreach(f: A => Unit): Unit = politelyFail 74 | 75 | def filter(predicate: A => Boolean): MySet[A] = new PropertyBasedSet[A](x => property(x) && predicate(x)) 76 | def -(elem: A): MySet[A] = filter(x => x != elem) 77 | def --(anotherSet: MySet[A]): MySet[A] = filter(!anotherSet) 78 | def &(anotherSet: MySet[A]): MySet[A] = filter(anotherSet) 79 | def unary_! : MySet[A] = new PropertyBasedSet[A](x => !property(x)) 80 | 81 | def politelyFail = throw new IllegalArgumentException("Really deep rabbit hole!") 82 | } 83 | 84 | class NonEmptySet[A](head: A, tail: MySet[A]) extends MySet[A] { 85 | def contains(elem: A): Boolean = 86 | elem == head || tail.contains(elem) 87 | 88 | def +(elem: A): MySet[A] = 89 | if (this contains elem) this 90 | else new NonEmptySet[A](elem, this) 91 | 92 | /* 93 | [1 2 3] ++ [4 5] = 94 | [2 3] ++ [4 5] + 1 = 95 | [3] ++ [4 5] + 1 + 2 = 96 | [] ++ [4 5] + 1 + 2 + 3 97 | [4 5] + 1 + 2 + 3 = [4 5 1 2 3] 98 | */ 99 | def ++(anotherSet: MySet[A]): MySet[A] = 100 | tail ++ anotherSet + head 101 | 102 | def map[B](f: A => B): MySet[B] = (tail map f) + f(head) 103 | def flatMap[B](f: A => MySet[B]): MySet[B] = (tail flatMap f) ++ f(head) 104 | def filter(predicate: A => Boolean): MySet[A] = { 105 | val filteredTail = tail filter predicate 106 | if (predicate(head)) filteredTail + head 107 | else filteredTail 108 | } 109 | 110 | def foreach(f: A => Unit): Unit = { 111 | f(head) 112 | tail foreach f 113 | } 114 | 115 | // part 2 116 | def -(elem: A): MySet[A] = 117 | if (head == elem) tail 118 | else tail - elem + head 119 | 120 | def --(anotherSet: MySet[A]): MySet[A] = filter(!anotherSet) 121 | def &(anotherSet: MySet[A]): MySet[A] = filter(anotherSet) // intersection = filtering! 122 | 123 | // new operator 124 | def unary_! : MySet[A] = new PropertyBasedSet[A](x => !this.contains(x)) 125 | } 126 | 127 | object MySet { 128 | /* 129 | val s = MySet(1,2,3) = buildSet(seq(1,2,3), []) 130 | = buildSet(seq(2,3), [] + 1) 131 | = buildSet(seq(3), [1] + 2) 132 | = buildSet(seq(), [1, 2] + 3) 133 | = [1,2,3] 134 | */ 135 | def apply[A](values: A*): MySet[A] = { 136 | @tailrec 137 | def buildSet(valSeq: Seq[A], acc: MySet[A]): MySet[A] = 138 | if (valSeq.isEmpty) acc 139 | else buildSet(valSeq.tail, acc + valSeq.head) 140 | 141 | buildSet(values, new EmptySet[A]) 142 | } 143 | } 144 | 145 | object MySetPlayground extends App { 146 | val s = MySet(1,2,3,4) 147 | s + 5 ++ MySet(-1, -2) + 3 flatMap (x => MySet(x, 10 * x)) filter (_ % 2 == 0) foreach println 148 | 149 | 150 | val negative = !s // s.unary_! = all the naturals not equal to 1,2,3,4 151 | println(negative(2)) 152 | println(negative(5)) 153 | 154 | val negativeEven = negative.filter(_ % 2 == 0) 155 | println(negativeEven(5)) 156 | 157 | val negativeEven5 = negativeEven + 5 // all the even numbers > 4 + 5 158 | println(negativeEven5(5)) 159 | } 160 | -------------------------------------------------------------------------------- /src/exercises/StreamsPlayground.scala: -------------------------------------------------------------------------------- 1 | package exercises 2 | 3 | import scala.annotation.tailrec 4 | 5 | 6 | /** 7 | * Created by Daniel. 8 | */ 9 | 10 | abstract class MyStream[+A] { 11 | def isEmpty: Boolean 12 | def head: A 13 | def tail: MyStream[A] 14 | 15 | def #::[B >: A](element: B): MyStream[B] // prepend operator 16 | def ++[B >: A](anotherStream: => MyStream[B]): MyStream[B] // concatenate two streams 17 | 18 | def foreach(f: A => Unit): Unit 19 | def map[B](f: A => B): MyStream[B] 20 | def flatMap[B](f: A => MyStream[B]): MyStream[B] 21 | def filter(predicate: A => Boolean): MyStream[A] 22 | 23 | def take(n: Int): MyStream[A] // takes the first n elements out of this stream 24 | def takeAsList(n: Int): List[A] = take(n).toList() 25 | 26 | /* 27 | [1 2 3].toList([]) = 28 | [2 3].toList([1]) = 29 | [3].toList([2 1]) = 30 | [].toList([3 2 1]) 31 | = [1 2 3] 32 | */ 33 | @tailrec 34 | final def toList[B >: A](acc: List[B] = Nil): List[B] = 35 | if (isEmpty) acc.reverse 36 | else tail.toList(head :: acc) 37 | } 38 | 39 | object EmptyStream extends MyStream[Nothing] { 40 | def isEmpty: Boolean = true 41 | def head: Nothing = throw new NoSuchElementException 42 | def tail: MyStream[Nothing] = throw new NoSuchElementException 43 | 44 | def #::[B >: Nothing](element: B): MyStream[B] = new Cons(element, this) 45 | def ++[B >: Nothing](anotherStream: => MyStream[B]): MyStream[B] = anotherStream 46 | 47 | def foreach(f: Nothing => Unit): Unit = () 48 | def map[B](f: Nothing => B): MyStream[B] = this 49 | def flatMap[B](f: Nothing => MyStream[B]): MyStream[B] = this 50 | def filter(predicate: Nothing => Boolean): MyStream[Nothing] = this 51 | 52 | def take(n: Int): MyStream[Nothing] = this 53 | } 54 | 55 | class Cons[+A](hd: A, tl: => MyStream[A]) extends MyStream[A] { 56 | def isEmpty: Boolean = false 57 | 58 | override val head: A = hd 59 | override lazy val tail: MyStream[A] = tl // call by need 60 | /* 61 | val s = new Cons(1, EmptyStream) 62 | val prepended = 1 #:: s = new Cons(1, s) 63 | */ 64 | def #::[B >: A](element: B): MyStream[B] = new Cons(element, this) 65 | def ++[B >: A](anotherStream: => MyStream[B]): MyStream[B] = new Cons(head, tail ++ anotherStream) 66 | 67 | def foreach(f: A => Unit): Unit = { 68 | f(head) 69 | tail.foreach(f) 70 | } 71 | 72 | /* 73 | s = new Cons(1, ?) 74 | mapped = s.map(_ + 1) = new Cons(2, s.tail.map(_ + 1)) 75 | ... mapped.tail 76 | */ 77 | def map[B](f: A => B): MyStream[B] = new Cons(f(head), tail.map(f)) // preserves lazy evaluation 78 | def flatMap[B](f: A => MyStream[B]): MyStream[B] = f(head) ++ tail.flatMap(f) 79 | def filter(predicate: A => Boolean): MyStream[A] = 80 | if (predicate(head)) new Cons(head, tail.filter(predicate)) 81 | else tail.filter(predicate) // preserves lazy eval! 82 | 83 | def take(n: Int): MyStream[A] = 84 | if (n <= 0) EmptyStream 85 | else if (n == 1) new Cons(head, EmptyStream) 86 | else new Cons(head, tail.take(n-1)) 87 | } 88 | 89 | object MyStream { 90 | def from[A](start: A)(generator: A => A): MyStream[A] = 91 | new Cons(start, MyStream.from(generator(start))(generator)) 92 | } 93 | 94 | 95 | object StreamsPlayground extends App{ 96 | val naturals = MyStream.from(1)(_ + 1) 97 | println(naturals.head) 98 | println(naturals.tail.head) 99 | println(naturals.tail.tail.head) 100 | 101 | val startFrom0 = 0 #:: naturals // naturals.#::(0) 102 | println(startFrom0.head) 103 | 104 | startFrom0.take(10000).foreach(println) 105 | 106 | // map, flatMap 107 | println(startFrom0.map(_ * 2).take(100).toList()) 108 | println(startFrom0.flatMap(x => new Cons(x, new Cons(x + 1, EmptyStream))).take(10).toList()) 109 | println(startFrom0.filter(_ < 10).take(10).take(20).toList()) 110 | 111 | // Exercises on streams 112 | // 1 - stream of Fibonacci numbers 113 | // 2 - stream of prime numbers with Eratosthenes' sieve 114 | /* 115 | [ 2 3 4 ... ] 116 | filter out all numbers divisible by 2 117 | [ 2 3 5 7 9 11 ...] 118 | filter out all numbers divisible by 3 119 | [ 2 3 5 7 11 13 17 ... ] 120 | filter out all numbers divisible by 5 121 | ... 122 | */ 123 | 124 | /* 125 | [ first, [ ... 126 | [ first, fibo(second, first + second) 127 | */ 128 | def fibonacci(first: BigInt, second: BigInt): MyStream[BigInt] = 129 | new Cons(first, fibonacci(second, first + second)) 130 | 131 | println(fibonacci(1, 1).take(100).toList()) 132 | 133 | /* 134 | [ 2 3 4 5 6 7 8 9 10 11 12 ... 135 | [ 2 3 5 7 9 11 13 ... 136 | [ 2 eratosthenes applied to (numbers filtered by n % 2 != 0) 137 | [ 2 3 eratosthenes applied to [ 5 7 9 11 ... ] filtered by n % 3 != 0 138 | [ 2 3 5 139 | */ 140 | // eratosthenes sieve 141 | def eratosthenes(numbers: MyStream[Int]): MyStream[Int] = 142 | if (numbers.isEmpty) numbers 143 | else new Cons(numbers.head, eratosthenes(numbers.tail.filter(_ % numbers.head != 0))) 144 | 145 | val primes = eratosthenes(MyStream.from(2)(_ + 1)) 146 | 147 | def isPrime(n: Int) = { 148 | def isPrimeRec(primesStream: MyStream[Int]): Boolean = 149 | if (primesStream.head > n / 2) true 150 | else if (n % primesStream.head == 0) false 151 | else isPrimeRec(primesStream.tail) 152 | 153 | isPrimeRec(primes) 154 | } 155 | 156 | primes.take(10000).foreach(println) 157 | 158 | } -------------------------------------------------------------------------------- /src/lectures/part1as/AdvancedPatternMatching.scala: -------------------------------------------------------------------------------- 1 | package lectures.part1as 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object AdvancedPatternMatching extends App { 7 | 8 | val numbers = List(1) 9 | val description = numbers match { 10 | case head :: Nil => println(s"the only element is $head.") 11 | case _ => 12 | } 13 | 14 | /* 15 | - constants 16 | - wildcards 17 | - case classes 18 | - tuples 19 | - some special magic like above 20 | */ 21 | 22 | class Person(val name: String, val age: Int) 23 | 24 | object Person { 25 | def unapply(person: Person): Option[(String, Int)] = 26 | if (person.age < 21) None 27 | else Some((person.name, person.age)) 28 | 29 | def unapply(age: Int): Option[String] = 30 | Some(if (age < 21) "minor" else "major") 31 | } 32 | 33 | val bob = new Person("Bob", 25) 34 | val greeting = bob match { 35 | case Person(n, a) => s"Hi, my name is $n and I am $a yo." 36 | } 37 | 38 | println(greeting) 39 | 40 | val legalStatus = bob.age match { 41 | case Person(status) => s"My legal status is $status" 42 | } 43 | 44 | println(legalStatus) 45 | 46 | /* 47 | Exercise. 48 | */ 49 | 50 | object even { 51 | def unapply(arg: Int): Boolean = arg % 2 == 0 52 | } 53 | 54 | object singleDigit { 55 | def unapply(arg: Int): Boolean = arg > -10 && arg < 10 56 | } 57 | 58 | val n: Int = 8 59 | val mathProperty = n match { 60 | case singleDigit() => "single digit" 61 | case even() => "an even number" 62 | case _ => "no property" 63 | } 64 | 65 | println(mathProperty) 66 | 67 | // infix patterns 68 | case class Or[A, B](a: A, b: B) 69 | val either = Or(2, "two") 70 | val humanDescription = either match { 71 | case number Or string => s"$number is written as $string" 72 | } 73 | println(humanDescription) 74 | 75 | // decomposing sequences 76 | val vararg = numbers match { 77 | case List(1, _*) => "starting with 1" 78 | } 79 | 80 | abstract class MyList[+A] { 81 | def head: A = ??? 82 | def tail: MyList[A] = ??? 83 | } 84 | case object Empty extends MyList[Nothing] 85 | case class Cons[+A](override val head: A, override val tail: MyList[A]) extends MyList[A] 86 | 87 | object MyList { 88 | def unapplySeq[A](list: MyList[A]): Option[Seq[A]] = 89 | if (list == Empty) Some(Seq.empty) 90 | else unapplySeq(list.tail).map(list.head +: _) 91 | } 92 | 93 | val myList: MyList[Int] = Cons(1, Cons(2, Cons(3, Empty))) 94 | val decomposed = myList match { 95 | case MyList(1, 2, _*) => "starting with 1, 2" 96 | case _ => "something else" 97 | } 98 | 99 | println(decomposed) 100 | 101 | // custom return types for unapply 102 | // isEmpty: Boolean, get: something. 103 | 104 | abstract class Wrapper[T] { 105 | def isEmpty: Boolean 106 | def get: T 107 | } 108 | 109 | object PersonWrapper { 110 | def unapply(person: Person): Wrapper[String] = new Wrapper[String] { 111 | def isEmpty = false 112 | def get= person.name 113 | } 114 | } 115 | 116 | println(bob match { 117 | case PersonWrapper(n) => s"This person's name is $n" 118 | case _ => "An alien" 119 | }) 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/lectures/part1as/DarkSugars.scala: -------------------------------------------------------------------------------- 1 | package lectures.part1as 2 | 3 | import scala.util.Try 4 | 5 | /** 6 | * Created by Daniel. 7 | */ 8 | object DarkSugars extends App { 9 | 10 | // syntax sugar #1: methods with single param 11 | def singleArgMethod(arg: Int): String = s"$arg little ducks..." 12 | 13 | val description = singleArgMethod { 14 | // write some complex code 15 | 42 16 | } 17 | 18 | val aTryInstance = Try { // java's try {...} 19 | throw new RuntimeException 20 | } 21 | 22 | List(1,2,3).map { x => 23 | x + 1 24 | } 25 | 26 | // syntax sugar #2: single abstract method 27 | trait Action { 28 | def act(x: Int): Int 29 | } 30 | 31 | val anInstance: Action = new Action { 32 | override def act(x: Int): Int = x + 1 33 | } 34 | 35 | val aFunkyInstance: Action = (x: Int) => x + 1 // magic 36 | 37 | // example: Runnables 38 | val aThread = new Thread(new Runnable { 39 | override def run(): Unit = println("hello, Scala") 40 | }) 41 | 42 | val aSweeterThread = new Thread(() => println("sweet, Scala!")) 43 | 44 | abstract class AnAbstractType { 45 | def implemented: Int = 23 46 | def f(a: Int): Unit 47 | } 48 | 49 | val anAbstractInstance: AnAbstractType = (a: Int) => println("sweet") 50 | 51 | // syntax sugar #3: the :: and #:: methods are special 52 | 53 | val prependedList = 2 :: List(3, 4) 54 | // 2.::(List(3,4)) 55 | // List(3,4).::(2) 56 | // ?! 57 | 58 | // scala spec: last char decides associativity of method 59 | 1 :: 2 :: 3 :: List(4, 5) 60 | List(4,5).::(3).::(2).::(1) // equivalent 61 | 62 | class MyStream[T] { 63 | def -->:(value: T): MyStream[T] = this // actual implementation here 64 | } 65 | 66 | val myStream = 1 -->: 2 -->: 3 -->: new MyStream[Int] 67 | 68 | // syntax sugar #4: multi-word method naming 69 | 70 | class TeenGirl(name: String) { 71 | def `and then said`(gossip: String) = println(s"$name said $gossip") 72 | } 73 | 74 | val lilly = new TeenGirl("Lilly") 75 | lilly `and then said` "Scala is so sweet!" 76 | 77 | // syntax sugar #5: infix types 78 | class Composite[A, B] 79 | val composite: Int Composite String = ??? 80 | 81 | class -->[A, B] 82 | val towards: Int --> String = ??? 83 | 84 | // syntax sugar #6: update() is very special, much like apply() 85 | val anArray = Array(1,2,3) 86 | anArray(2) = 7 // rewritten to anArray.update(2, 7) 87 | // used in mutable collections 88 | // remember apply() AND update()! 89 | 90 | // syntax sugar #7: setters for mutable containers 91 | class Mutable { 92 | private var internalMember: Int = 0 // private for OO encapsulation 93 | def member = internalMember // "getter" 94 | def member_=(value: Int): Unit = 95 | internalMember = value // "setter" 96 | } 97 | 98 | val aMutableContainer = new Mutable 99 | aMutableContainer.member = 42 // rewrittern as aMutableContainer.member_=(42) 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/lectures/part1as/Recap.scala: -------------------------------------------------------------------------------- 1 | package lectures.part1as 2 | 3 | import scala.annotation.tailrec 4 | 5 | 6 | /** 7 | * Created by Daniel. 8 | */ 9 | object Recap extends App { 10 | 11 | val aCondition: Boolean = false 12 | val aConditionedVal = if (aCondition) 42 else 65 13 | // instructions vs expressions 14 | 15 | // compiler infers types for us 16 | val aCodeBlock = { 17 | if (aCondition) 54 18 | 56 19 | } 20 | 21 | // Unit = void 22 | val theUnit = println("hello, Scala") 23 | 24 | // functions 25 | def aFunction(x: Int): Int = x + 1 26 | 27 | // recursion: stack and tail 28 | @tailrec def factorial(n: Int, accumulator: Int): Int = 29 | if (n <= 0) accumulator 30 | else factorial(n - 1, n * accumulator) 31 | 32 | // object-oriented programming 33 | 34 | class Animal 35 | class Dog extends Animal 36 | val aDog: Animal = new Dog // subtyping polymorphism 37 | 38 | trait Carnivore { 39 | def eat(a: Animal): Unit 40 | } 41 | 42 | class Crocodile extends Animal with Carnivore { 43 | override def eat(a: Animal): Unit = println("crunch!") 44 | } 45 | 46 | // method notations 47 | val aCroc = new Crocodile 48 | aCroc.eat(aDog) 49 | aCroc eat aDog // natural language 50 | 51 | // anonymous classes 52 | val aCarnivore = new Carnivore { 53 | override def eat(a: Animal): Unit = println("roar!") 54 | } 55 | 56 | // generics 57 | abstract class MyList[+A] // variance and variance problems in THIS course 58 | // singletons and companions 59 | object MyList 60 | 61 | // case classes 62 | case class Person(name: String, age: Int) 63 | 64 | // exceptions and try/catch/finally 65 | 66 | val throwsException = throw new RuntimeException // Nothing 67 | val aPotentialFailure = try { 68 | throw new RuntimeException 69 | } catch { 70 | case e: Exception => "I caught an exception" 71 | } finally { 72 | println("some logs") 73 | } 74 | 75 | // packaging and imports 76 | 77 | // functional programming 78 | val incrementer = new Function1[Int, Int] { 79 | override def apply(v1: Int): Int = v1 + 1 80 | } 81 | 82 | incrementer(1) 83 | 84 | val anonymousIncrementer = (x: Int) => x + 1 85 | List(1,2,3).map(anonymousIncrementer) // HOF 86 | // map, flatMap, filter 87 | 88 | // for-comprehension 89 | val pairs = for { 90 | num <- List(1,2,3) // if condition 91 | char <- List('a', 'b', 'c') 92 | } yield num + "-" + char 93 | 94 | // Scala collections: Seqs, Arrays, Lists, Vectors, Maps, Tuples 95 | val aMap = Map( 96 | "Daniel" -> 789, 97 | "Jess" -> 555 98 | ) 99 | 100 | // "collections": Options, Try 101 | val anOption = Some(2) 102 | 103 | // pattern matching 104 | val x = 2 105 | val order = x match { 106 | case 1 => "first" 107 | case 2 => "second" 108 | case 3 => "third" 109 | case _ => x + "th" 110 | } 111 | 112 | val bob = Person("Bob", 22) 113 | val greeting = bob match { 114 | case Person(n, _) => s"Hi, my name is $n" 115 | } 116 | 117 | // all the patterns 118 | } 119 | -------------------------------------------------------------------------------- /src/lectures/part2afp/CurriesPAF.scala: -------------------------------------------------------------------------------- 1 | package lectures.part2afp 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object CurriesPAF extends App { 7 | 8 | // curried functions 9 | val superAdder: Int => Int => Int = 10 | x => y => x + y 11 | 12 | val add3 = superAdder(3) // Int => Int = y => 3 + y 13 | println(add3(5)) 14 | println(superAdder(3)(5)) // curried function 15 | 16 | // METHOD! 17 | def curriedAdder(x: Int)(y: Int): Int = x + y // curried method 18 | 19 | val add4: Int => Int = curriedAdder(4) 20 | // lifting = ETA-EXPANSION 21 | 22 | // functions != methods (JVM limitation) 23 | def inc(x: Int) = x + 1 24 | List(1,2,3).map(x => inc(x)) // ETA-expansion 25 | 26 | // Partial function applications 27 | val add5 = curriedAdder(5) _ // Int => Int 28 | 29 | // EXERCISE 30 | val simpleAddFunction = (x: Int, y: Int) => x + y 31 | def simpleAddMethod(x: Int, y: Int) = x + y 32 | def curriedAddMethod(x: Int)(y: Int) = x + y 33 | 34 | // add7: Int => Int = y => 7 + y 35 | // as many different implementations of add7 using the above 36 | // be creative! 37 | val add7 = (x: Int) => simpleAddFunction(7, x) // simplest 38 | val add7_2 = simpleAddFunction.curried(7) 39 | val add7_6 = simpleAddFunction(7, _: Int) // works as well 40 | 41 | val add7_3 = curriedAddMethod(7) _ // PAF 42 | val add7_4 = curriedAddMethod(7)(_) // PAF = alternative syntax 43 | 44 | val add7_5 = simpleAddMethod(7, _: Int) // alternative syntax for turning methods into function values 45 | // y => simpleAddMethod(7, y) 46 | 47 | // underscores are powerful 48 | def concatenator(a: String, b: String, c: String) = a + b + c 49 | val insertName = concatenator("Hello, I'm ", _: String, ", how are you?") // x: String => concatenator(hello, x, howarewyou) 50 | println(insertName("Daniel")) 51 | 52 | val fillInTheBlanks = concatenator("Hello, ", _: String, _: String) // (x, y) => concatenator("Hello, ", x, y) 53 | println(fillInTheBlanks("Daniel", " Scala is awesome!")) 54 | 55 | // EXERCISES 56 | /* 57 | 1. Process a list of numbers and return their string representations with different formats 58 | Use the %4.2f, %8.6f and %14.12f with a curried formatter function. 59 | */ 60 | def curriedFormatter(s: String)(number: Double): String = s.format(number) 61 | val numbers = List(Math.PI, Math.E, 1, 9.8, 1.3e-12) 62 | 63 | val simpleFormat = curriedFormatter("%4.2f") _ // lift 64 | val seriousFormat = curriedFormatter("%8.6f") _ 65 | val preciseFormat = curriedFormatter("%14.12f") _ 66 | 67 | println(numbers.map(curriedFormatter("%14.12f"))) // compiler does sweet eta-expansion for us 68 | 69 | /* 70 | 2. difference between 71 | - functions vs methods 72 | - parameters: by-name vs 0-lambda 73 | */ 74 | def byName(n: => Int) = n + 1 75 | def byFunction(f: () => Int) = f() + 1 76 | 77 | def method: Int = 42 78 | def parenMethod(): Int = 42 79 | 80 | /* 81 | calling byName and byFunction 82 | - int 83 | - method 84 | - parenMethod 85 | - lambda 86 | - PAF 87 | */ 88 | byName(23) // ok 89 | byName(method) // ok 90 | byName(parenMethod()) 91 | byName(parenMethod) // ok but beware ==> byName(parenMethod()) 92 | // byName(() => 42) // not ok 93 | byName((() => 42)()) // ok 94 | // byName(parenMethod _) // not ok 95 | 96 | // byFunction(45) // not ok 97 | // byFunction(method) // not ok!!!!!! does not do ETA-expansion! 98 | byFunction(parenMethod) // compiler does ETA-expansion 99 | byFunction(() => 46) // works 100 | byFunction(parenMethod _) // also works, but warning- unnecessary 101 | } 102 | 103 | -------------------------------------------------------------------------------- /src/lectures/part2afp/LazyEvaluation.scala: -------------------------------------------------------------------------------- 1 | package lectures.part2afp 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object LazyEvaluation extends App { 7 | 8 | // lazy DELAYS the evaluation of values 9 | lazy val x: Int = { 10 | println("hello") 11 | 42 12 | } 13 | println(x) 14 | println(x) 15 | 16 | // examples of implications: 17 | // side effects 18 | def sideEffectCondition: Boolean = { 19 | println("Boo") 20 | true 21 | } 22 | def simpleCondition: Boolean = false 23 | 24 | lazy val lazyCondition = sideEffectCondition 25 | println(if (simpleCondition && lazyCondition) "yes" else "no") 26 | 27 | // in conjunction with call by name 28 | def byNameMethod(n: => Int): Int = { 29 | // CALL BY NEED 30 | lazy val t = n // only evaluated once 31 | t + t + t + 1 32 | } 33 | def retrieveMagicValue = { 34 | // side effect or a long computation 35 | println("waiting") 36 | Thread.sleep(1000) 37 | 42 38 | } 39 | 40 | println(byNameMethod(retrieveMagicValue)) 41 | // use lazy vals 42 | 43 | // filtering with lazy vals 44 | def lessThan30(i: Int): Boolean = { 45 | println(s"$i is less than 30?") 46 | i < 30 47 | } 48 | 49 | def greaterThan20(i: Int): Boolean = { 50 | println(s"$i is greater than 20?") 51 | i > 20 52 | } 53 | 54 | val numbers = List(1, 25, 40, 5, 23) 55 | val lt30 = numbers.filter(lessThan30) // List(1, 25, 5, 23) 56 | val gt20 = lt30.filter(greaterThan20) 57 | println(gt20) 58 | 59 | val lt30lazy = numbers.withFilter(lessThan30) // lazy vals under the hood 60 | val gt20lazy = lt30lazy.withFilter(greaterThan20) 61 | println 62 | gt20lazy.foreach(println) 63 | 64 | // for-comprehensions use withFilter with guards 65 | for { 66 | a <- List(1,2,3) if a % 2 == 0 // use lazy vals! 67 | } yield a + 1 68 | List(1,2,3).withFilter(_ % 2 == 0).map(_ + 1) // List[Int] 69 | 70 | /* 71 | Exercise: implement a lazily evaluated, singly linked STREAM of elements. 72 | 73 | naturals = MyStream.from(1)(x => x + 1) = stream of natural numbers (potentially infinite!) 74 | naturals.take(100).foreach(println) // lazily evaluated stream of the first 100 naturals (finite stream) 75 | naturals.foreach(println) // will crash - infinite! 76 | naturals.map(_ * 2) // stream of all even numbers (potentially infinite) 77 | */ 78 | abstract class MyStream[+A] { 79 | def isEmpty: Boolean 80 | def head: A 81 | def tail: MyStream[A] 82 | 83 | def #::[B >: A](element: B): MyStream[B] // prepend operator 84 | def ++[B >: A](anotherStream: MyStream[B]): MyStream[B] // concatenate two streams 85 | 86 | def foreach(f: A => Unit): Unit 87 | def map[B](f: A => B): MyStream[B] 88 | def flatMap[B](f: A => MyStream[B]): MyStream[B] 89 | def filter(predicate: A => Boolean): MyStream[A] 90 | 91 | def take(n: Int): MyStream[A] // takes the first n elements out of this stream 92 | def takeAsList(n: Int): List[A] 93 | } 94 | 95 | object MyStream { 96 | def from[A](start: A)(generator: A => A): MyStream[A] = ??? 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/lectures/part2afp/Monads.scala: -------------------------------------------------------------------------------- 1 | package lectures.part2afp 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object Monads extends App { 7 | 8 | // our own Try monad 9 | 10 | trait Attempt[+A] { 11 | def flatMap[B](f: A => Attempt[B]): Attempt[B] 12 | } 13 | object Attempt { 14 | def apply[A](a: => A): Attempt[A] = 15 | try { 16 | Success(a) 17 | } catch { 18 | case e: Throwable => Fail(e) 19 | } 20 | } 21 | 22 | case class Success[+A](value: A) extends Attempt[A] { 23 | def flatMap[B](f: A => Attempt[B]): Attempt[B] = 24 | try { 25 | f(value) 26 | } catch { 27 | case e: Throwable => Fail(e) 28 | } 29 | } 30 | 31 | case class Fail(e: Throwable) extends Attempt[Nothing] { 32 | def flatMap[B](f: Nothing => Attempt[B]): Attempt[B] = this 33 | } 34 | 35 | /* 36 | left-identity 37 | 38 | unit.flatMap(f) = f(x) 39 | Attempt(x).flatMap(f) = f(x) // Success case! 40 | Success(x).flatMap(f) = f(x) // proved. 41 | 42 | right-identity 43 | 44 | attempt.flatMap(unit) = attempt 45 | Success(x).flatMap(x => Attempt(x)) = Attempt(x) = Success(x) 46 | Fail(e).flatMap(...) = Fail(e) 47 | 48 | associativity 49 | 50 | attempt.flatMap(f).flatMap(g) == attempt.flatMap(x => f(x).flatMap(g)) 51 | Fail(e).flatMap(f).flatMap(g) = Fail(e) 52 | Fail(e).flatMap(x => f(x).flatMap(g)) = Fail(e) 53 | 54 | Success(v).flatMap(f).flatMap(g) = 55 | f(v).flatMap(g) OR Fail(e) 56 | 57 | Success(v).flatMap(x => f(x).flatMap(g)) = 58 | f(v).flatMap(g) OR Fail(e) 59 | 60 | */ 61 | 62 | val attempt = Attempt { 63 | throw new RuntimeException("My own monad, yes!") 64 | } 65 | 66 | println(attempt) 67 | 68 | /* 69 | EXERCISE: 70 | 1) implement a Lazy[T] monad = computation which will only be executed when it's needed. 71 | unit/apply 72 | flatMap 73 | 74 | 2) Monads = unit + flatMap 75 | Monads = unit + map + flatten 76 | 77 | Monad[T] { 78 | 79 | def flatMap[B](f: T => Monad[B]): Monad[B] = ... (implemented) 80 | 81 | def map[B](f: T => B): Monad[B] = ??? 82 | def flatten(m: Monad[Monad[T]]): Monad[T] = ??? 83 | 84 | (have List in mind) 85 | */ 86 | 87 | // 1 - Lazy monad 88 | class Lazy[+A](value: => A) { 89 | // call by need 90 | private lazy val internalValue = value 91 | def use: A = internalValue 92 | def flatMap[B](f: (=> A) => Lazy[B]): Lazy[B] = f(internalValue) 93 | } 94 | object Lazy { 95 | def apply[A](value: => A): Lazy[A] = new Lazy(value) // unit 96 | } 97 | 98 | val lazyInstance = Lazy { 99 | println("Today I don't feel like doing anything") 100 | 42 101 | } 102 | 103 | val flatMappedInstance = lazyInstance.flatMap(x => Lazy { 104 | 10 * x 105 | }) 106 | val flatMappedInstance2 = lazyInstance.flatMap(x => Lazy { 107 | 10 * x 108 | }) 109 | flatMappedInstance.use 110 | flatMappedInstance2.use 111 | 112 | /* 113 | left-identity 114 | unit.flatMap(f) = f(v) 115 | Lazy(v).flatMap(f) = f(v) 116 | 117 | right-identity 118 | l.flatMap(unit) = l 119 | Lazy(v).flatMap(x => Lazy(x)) = Lazy(v) 120 | 121 | associativity: l.flatMap(f).flatMap(g) = l.flatMap(x => f(x).flatMap(g)) 122 | 123 | Lazy(v).flatMap(f).flatMap(g) = f(v).flatMap(g) 124 | Lazy(v).flatMap(x => f(x).flatMap(g)) = f(v).flatMap(g) 125 | */ 126 | 127 | def flatten[T](lz: Lazy[Lazy[T]]): Lazy[T] = lz.flatMap(x => x) 128 | // 2: map and flatten in terms of flatMap 129 | /* 130 | Monad[T] { // List 131 | def flatMap[B](f: T => Monad[B]): Monad[B] = ... (implemented) 132 | 133 | def map[B](f: T => B): Monad[B] = flatMap(x => unit(f(x))) // Monad[B] 134 | def flatten(m: Monad[Monad[T]]): Monad[T] = m.flatMap((x: Monad[T]) => x) 135 | 136 | List(1,2,3).map(_ * 2) = List(1,2,3).flatMap(x => List(x * 2)) 137 | List(List(1, 2), List(3, 4)).flatten = List(List(1, 2), List(3, 4)).flatMap(x => x) = List(1,2,3,4) 138 | } 139 | 140 | */ 141 | } 142 | -------------------------------------------------------------------------------- /src/lectures/part2afp/PartialFunctions.scala: -------------------------------------------------------------------------------- 1 | package lectures.part2afp 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object PartialFunctions extends App { 7 | 8 | val aFunction = (x: Int) => x + 1 // Function1[Int, Int] === Int => Int 9 | 10 | val aFussyFunction = (x: Int) => 11 | if (x == 1) 42 12 | else if (x == 2) 56 13 | else if (x == 5) 999 14 | else throw new FunctionNotApplicableException 15 | 16 | class FunctionNotApplicableException extends RuntimeException 17 | 18 | val aNicerFussyFunction = (x: Int) => x match { 19 | case 1 => 42 20 | case 2 => 56 21 | case 5 => 999 22 | } 23 | // {1,2,5} => Int 24 | 25 | val aPartialFunction: PartialFunction[Int, Int] = { 26 | case 1 => 42 27 | case 2 => 56 28 | case 5 => 999 29 | } // partial function value 30 | 31 | println(aPartialFunction(2)) 32 | // println(aPartialFunction(57273)) 33 | 34 | // PF utilities 35 | println(aPartialFunction.isDefinedAt(67)) 36 | 37 | // lift 38 | val lifted = aPartialFunction.lift // Int => Option[Int] 39 | println(lifted(2)) 40 | println(lifted(98)) 41 | 42 | val pfChain = aPartialFunction.orElse[Int, Int] { 43 | case 45 => 67 44 | } 45 | 46 | println(pfChain(2)) 47 | println(pfChain(45)) 48 | 49 | // PF extend normal functions 50 | 51 | val aTotalFunction: Int => Int = { 52 | case 1 => 99 53 | } 54 | 55 | // HOFs accept partial functions as well 56 | val aMappedList = List(1,2,3).map { 57 | case 1 => 42 58 | case 2 => 78 59 | case 3 => 1000 60 | } 61 | println(aMappedList) 62 | 63 | /* 64 | Note: PF can only have ONE parameter type 65 | */ 66 | 67 | /** 68 | * Exercises 69 | * 70 | * 1 - construct a PF instance yourself (anonymous class) 71 | * 2 - dumb chatbot as a PF 72 | */ 73 | 74 | val aManualFussyFunction = new PartialFunction[Int, Int] { 75 | override def apply(x: Int): Int = x match { 76 | case 1 => 42 77 | case 2 => 65 78 | case 5 => 999 79 | } 80 | 81 | override def isDefinedAt(x: Int): Boolean = 82 | x == 1 || x == 2 || x == 5 83 | } 84 | 85 | val chatbot: PartialFunction[String, String] = { 86 | case "hello" => "Hi, my name is HAL9000" 87 | case "goodbye" => "Once you start talking to me, there is no return, human!" 88 | case "call mom" => "Unable to find your phone without your credit card" 89 | } 90 | 91 | scala.io.Source.stdin.getLines().map(chatbot).foreach(println) 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/lectures/part3concurrency/FuturesPromises.scala: -------------------------------------------------------------------------------- 1 | package lectures.part3concurrency 2 | 3 | import scala.concurrent.{Await, Future, Promise} 4 | import scala.util.{Failure, Random, Success, Try} 5 | import scala.concurrent.duration._ 6 | 7 | // important for futures 8 | import scala.concurrent.ExecutionContext.Implicits.global 9 | /** 10 | * Created by Daniel. 11 | */ 12 | object FuturesPromises extends App { 13 | 14 | def calculateMeaningOfLife: Int = { 15 | Thread.sleep(2000) 16 | 42 17 | } 18 | 19 | val aFuture = Future { 20 | calculateMeaningOfLife // calculates the meaning of life on ANOTHER thread 21 | } // (global) which is passed by the compiler 22 | 23 | 24 | println(aFuture.value) // Option[Try[Int]] 25 | 26 | println("Waiting on the future") 27 | aFuture.onComplete { 28 | case Success(meaningOfLife) => println(s"the meaning of life is $meaningOfLife") 29 | case Failure(e) => println(s"I have failed with $e") 30 | } // SOME thread 31 | 32 | Thread.sleep(3000) 33 | 34 | // mini social network 35 | 36 | case class Profile(id: String, name: String) { 37 | def poke(anotherProfile: Profile) = 38 | println(s"${this.name} poking ${anotherProfile.name}") 39 | } 40 | 41 | object SocialNetwork { 42 | // "database" 43 | val names = Map( 44 | "fb.id.1-zuck" -> "Mark", 45 | "fb.id.2-bill" -> "Bill", 46 | "fb.id.0-dummy" -> "Dummy" 47 | ) 48 | val friends = Map( 49 | "fb.id.1-zuck" -> "fb.id.2-bill" 50 | ) 51 | 52 | val random = new Random() 53 | 54 | // API 55 | def fetchProfile(id: String): Future[Profile] = Future { 56 | // fetching from the DB 57 | Thread.sleep(random.nextInt(300)) 58 | Profile(id, names(id)) 59 | } 60 | 61 | def fetchBestFriend(profile: Profile): Future[Profile] = Future { 62 | Thread.sleep(random.nextInt(400)) 63 | val bfId = friends(profile.id) 64 | Profile(bfId, names(bfId)) 65 | } 66 | } 67 | 68 | // client: mark to poke bill 69 | val mark = SocialNetwork.fetchProfile("fb.id.1-zuck") 70 | // mark.onComplete { 71 | // case Success(markProfile) => { 72 | // val bill = SocialNetwork.fetchBestFriend(markProfile) 73 | // bill.onComplete { 74 | // case Success(billProfile) => markProfile.poke(billProfile) 75 | // case Failure(e) => e.printStackTrace() 76 | // } 77 | // } 78 | // case Failure(ex) => ex.printStackTrace() 79 | // } 80 | 81 | 82 | // functional composition of futures 83 | // map, flatMap, filter 84 | val nameOnTheWall = mark.map(profile => profile.name) 85 | val marksBestFriend = mark.flatMap(profile => SocialNetwork.fetchBestFriend(profile)) 86 | val zucksBestFriendRestricted = marksBestFriend.filter(profile => profile.name.startsWith("Z")) 87 | 88 | // for-comprehensions 89 | for { 90 | mark <- SocialNetwork.fetchProfile("fb.id.1-zuck") 91 | bill <- SocialNetwork.fetchBestFriend(mark) 92 | } mark.poke(bill) 93 | 94 | Thread.sleep(1000) 95 | 96 | // fallbacks 97 | val aProfileNoMatterWhat = SocialNetwork.fetchProfile("unknown id").recover { 98 | case e: Throwable => Profile("fb.id.0-dummy", "Forever alone") 99 | } 100 | 101 | val aFetchedProfileNoMatterWhat = SocialNetwork.fetchProfile("unknown id").recoverWith { 102 | case e: Throwable => SocialNetwork.fetchProfile("fb.id.0-dummy") 103 | } 104 | 105 | val fallbackResult = SocialNetwork.fetchProfile("unknown id").fallbackTo(SocialNetwork.fetchProfile("fb.id.0-dummy")) 106 | 107 | // online banking app 108 | case class User(name: String) 109 | case class Transaction(sender: String, receiver: String, amount: Double, status: String) 110 | 111 | object BankingApp { 112 | val name = "Rock the JVM banking" 113 | 114 | def fetchUser(name: String): Future[User] = Future { 115 | // simulate fetching from the DB 116 | Thread.sleep(500) 117 | User(name) 118 | } 119 | 120 | def createTransaction(user: User, merchantName: String, amount: Double): Future[Transaction] = Future { 121 | // simulate some processes 122 | Thread.sleep(1000) 123 | Transaction(user.name, merchantName, amount, "SUCCESS") 124 | } 125 | 126 | def purchase(username: String, item: String, merchantName: String, cost: Double): String = { 127 | // fetch the user from the DB 128 | // create a transaction 129 | // WAIT for the transaction to finish 130 | val transactionStatusFuture = for { 131 | user <- fetchUser(username) 132 | transaction <- createTransaction(user, merchantName, cost) 133 | } yield transaction.status 134 | 135 | Await.result(transactionStatusFuture, 2.seconds) // implicit conversions -> pimp my library 136 | } 137 | } 138 | 139 | println(BankingApp.purchase("Daniel", "iPhone 12", "rock the jvm store", 3000)) 140 | 141 | // promises 142 | 143 | val promise = Promise[Int]() // "controller" over a future 144 | val future = promise.future 145 | 146 | // thread 1 - "consumer" 147 | future.onComplete { 148 | case Success(r) => println("[consumer] I've received " + r) 149 | } 150 | 151 | // thread 2 - "producer" 152 | val producer = new Thread(() => { 153 | println("[producer] crunching numbers...") 154 | Thread.sleep(500) 155 | // "fulfilling" the promise 156 | promise.success(42) 157 | println("[producer] done") 158 | }) 159 | 160 | producer.start() 161 | Thread.sleep(1000) 162 | 163 | /* 164 | 1) fulfill a future IMMEDIATELY with a value 165 | 2) inSequence(fa, fb) 166 | 3) first(fa, fb) => new future with the first value of the two futures 167 | 4) last(fa, fb) => new future with the last value 168 | 5) retryUntil[T](action: () => Future[T], condition: T => Boolean): Future[T] 169 | */ 170 | 171 | // 1 - fulfill immediately 172 | def fulfillImmediately[T](value: T): Future[T] = Future(value) 173 | // 2 - insequence 174 | def inSequence[A, B](first: Future[A], second: Future[B]): Future[B] = 175 | first.flatMap(_ => second) 176 | 177 | // 3 - first out of two futures 178 | def first[A](fa: Future[A], fb: Future[A]): Future[A] = { 179 | val promise = Promise[A] 180 | fa.onComplete(promise.tryComplete) 181 | fb.onComplete(promise.tryComplete) 182 | 183 | promise.future 184 | } 185 | 186 | // 4 - last out of the two futures 187 | def last[A](fa: Future[A], fb: Future[A]): Future[A] = { 188 | // 1 promise which both futures will try to complete 189 | // 2 promise which the LAST future will complete 190 | val bothPromise = Promise[A] 191 | val lastPromise = Promise[A] 192 | val checkAndComplete = (result: Try[A]) => 193 | if(!bothPromise.tryComplete(result)) 194 | lastPromise.complete(result) 195 | 196 | fa.onComplete(checkAndComplete) 197 | fb.onComplete(checkAndComplete) 198 | 199 | lastPromise.future 200 | } 201 | 202 | val fast = Future { 203 | Thread.sleep(100) 204 | 42 205 | } 206 | 207 | val slow = Future { 208 | Thread.sleep(200) 209 | 45 210 | } 211 | first(fast, slow).foreach(f => println("FIRST: " + f)) 212 | last(fast, slow).foreach(l => println("LAST: " + l)) 213 | 214 | Thread.sleep(1000) 215 | 216 | // retry until 217 | def retryUntil[A](action: () => Future[A], condition: A => Boolean): Future[A] = 218 | action() 219 | .filter(condition) 220 | .recoverWith { 221 | case _ => retryUntil(action, condition) 222 | } 223 | 224 | val random = new Random() 225 | val action = () => Future { 226 | Thread.sleep(100) 227 | val nextValue = random.nextInt(100) 228 | println("generated " + nextValue) 229 | nextValue 230 | } 231 | 232 | retryUntil(action, (x: Int) => x < 10).foreach(result => println("settled at " + result)) 233 | Thread.sleep(10000) 234 | } 235 | -------------------------------------------------------------------------------- /src/lectures/part3concurrency/Intro.scala: -------------------------------------------------------------------------------- 1 | package lectures.part3concurrency 2 | 3 | import java.util.concurrent.Executors 4 | 5 | /** 6 | * Created by Daniel. 7 | */ 8 | object Intro extends App { 9 | 10 | /* 11 | interface Runnable { 12 | public void run() 13 | } 14 | */ 15 | // JVM threads 16 | val runnable = new Runnable { 17 | override def run(): Unit = println("Running in parallel") 18 | } 19 | val aThread = new Thread(runnable) 20 | 21 | aThread.start() // gives the signal to the JVM to start a JVM thread 22 | // create a JVM thread => OS thread 23 | runnable.run() // doesn't do anything in parallel! 24 | aThread.join() // blocks until aThread finishes running 25 | 26 | val threadHello = new Thread(() => (1 to 5).foreach(_ => println("hello"))) 27 | val threadGoodbye = new Thread(() => (1 to 5).foreach(_ => println("goodbye"))) 28 | // threadHello.start() 29 | // threadGoodbye.start() 30 | // different runs produce different results! 31 | 32 | // executors 33 | val pool = Executors.newFixedThreadPool(10) 34 | // pool.execute(() => println("something in the thread pool")) 35 | 36 | // pool.execute(() => { 37 | // Thread.sleep(1000) 38 | // println("done after 1 second") 39 | // }) 40 | // 41 | // pool.execute(() => { 42 | // Thread.sleep(1000) 43 | // println("almost done") 44 | // Thread.sleep(1000) 45 | // println("done after 2 seconds") 46 | // }) 47 | 48 | pool.shutdown() 49 | // pool.execute(() => println("should not appear")) // throws an exception in the calling thread 50 | 51 | // pool.shutdownNow() 52 | println(pool.isShutdown) // true 53 | 54 | def runInParallel = { 55 | var x = 0 56 | 57 | val thread1 = new Thread(() => { 58 | x = 1 59 | }) 60 | 61 | val thread2 = new Thread(() => { 62 | x = 2 63 | }) 64 | 65 | thread1.start() 66 | thread2.start() 67 | println(x) 68 | } 69 | 70 | // for (_ <- 1 to 10000) runInParallel 71 | // race condition 72 | 73 | class BankAccount(@volatile var amount: Int) { 74 | override def toString: String = "" + amount 75 | } 76 | 77 | def buy(account: BankAccount, thing: String, price: Int) = { 78 | account.amount -= price // account.amount = account.amount - price 79 | // println("I've bought " + thing) 80 | // println("my account is now " + account) 81 | } 82 | 83 | // for (_ <- 1 to 10000) { 84 | // val account = new BankAccount(50000) 85 | // val thread1 = new Thread(() => buy(account, "shoes", 3000)) 86 | // val thread2 = new Thread(() => buy(account, "iPhone12", 4000)) 87 | // 88 | // thread1.start() 89 | // thread2.start() 90 | // Thread.sleep(10) 91 | // if (account.amount != 43000) println("AHA: " + account.amount) 92 | //// println() 93 | // } 94 | 95 | /* 96 | thread1 (shoes): 50000 97 | - account = 50000 - 3000 = 47000 98 | thread2 (iphone): 50000 99 | - account = 50000 - 4000 = 46000 overwrites the memory of account.amount 100 | */ 101 | 102 | // option #1: use synchronized() 103 | def buySafe(account: BankAccount, thing: String, price: Int) = 104 | account.synchronized { 105 | // no two threads can evaluate this at the same time 106 | account.amount -= price 107 | println("I've bought " + thing) 108 | println("my account is now " + account) 109 | } 110 | 111 | // option #2: use @volatile 112 | 113 | /** 114 | * Exercises 115 | * 116 | * 1) Construct 50 "inception" threads 117 | * Thread1 -> thread2 -> thread3 -> ... 118 | * println("hello from thread #3") 119 | * in REVERSE ORDER 120 | * 121 | */ 122 | def inceptionThreads(maxThreads: Int, i: Int = 1): Thread = new Thread(() => { 123 | if (i < maxThreads) { 124 | val newThread = inceptionThreads(maxThreads, i + 1) 125 | newThread.start() 126 | newThread.join() 127 | } 128 | println(s"Hello from thread $i") 129 | }) 130 | 131 | inceptionThreads(50).start() 132 | 133 | /* 134 | 2 135 | */ 136 | var x = 0 137 | val threads = (1 to 100).map(_ => new Thread(() => x += 1)) 138 | threads.foreach(_.start()) 139 | /* 140 | 1) what is the biggest value possible for x? 100 141 | 2) what is the SMALLEST value possible for x? 1 142 | 143 | thread1: x = 0 144 | thread2: x = 0 145 | ... 146 | thread100: x = 0 147 | 148 | for all threads: x = 1 and write it back to x 149 | */ 150 | threads.foreach(_.join()) 151 | println(x) 152 | 153 | /* 154 | 3 sleep fallacy 155 | */ 156 | var message = "" 157 | val awesomeThread = new Thread(() => { 158 | Thread.sleep(1000) 159 | message = "Scala is awesome" 160 | }) 161 | 162 | message = "Scala sucks" 163 | awesomeThread.start() 164 | Thread.sleep(1001) 165 | awesomeThread.join() // wait for the awesome thread to join 166 | println(message) 167 | /* 168 | what's the value of message? almost always "Scala is awesome" 169 | is it guaranteed? NO! 170 | why? why not? 171 | 172 | (main thread) 173 | message = "Scala sucks" 174 | awesomeThread.start() 175 | sleep() - relieves execution 176 | (awesome thread) 177 | sleep() - relieves execution 178 | (OS gives the CPU to some important thread - takes CPU for more than 2 seconds) 179 | (OS gives the CPU back to the MAIN thread) 180 | println("Scala sucks") 181 | (OS gives the CPU to awesomethread) 182 | message = "Scala is awesome" 183 | 184 | */ 185 | 186 | // how do we fix this? 187 | // syncrhonizing does NOT work 188 | 189 | 190 | } 191 | 192 | -------------------------------------------------------------------------------- /src/lectures/part3concurrency/ParallelUtils.scala: -------------------------------------------------------------------------------- 1 | package lectures.part3concurrency 2 | 3 | import java.util.concurrent.atomic.AtomicReference 4 | 5 | import scala.collection.parallel.{ForkJoinTaskSupport, Task, TaskSupport} 6 | import scala.collection.parallel.immutable.ParVector 7 | import scala.concurrent.forkjoin.ForkJoinPool 8 | 9 | /** 10 | * Created by Daniel. 11 | */ 12 | object ParallelUtils extends App { 13 | 14 | // 1 - parallel collections 15 | 16 | val parList = List(1,2,3).par 17 | 18 | val aParVector = ParVector[Int](1,2,3) 19 | 20 | /* 21 | Seq 22 | Vector 23 | Array 24 | Map - Hash, Trie 25 | Set - Hash, Trie 26 | */ 27 | 28 | def measure[T](operation: => T): Long = { 29 | val time = System.currentTimeMillis() 30 | operation 31 | System.currentTimeMillis() - time 32 | } 33 | 34 | val list = (1 to 10000).toList 35 | val serialTime = measure { 36 | list.map(_ + 1) 37 | } 38 | println("serial time: " + serialTime) 39 | 40 | val parallelTime = measure { 41 | list.par.map(_ + 1) 42 | } 43 | 44 | println("parallel time: " + parallelTime) 45 | 46 | /* 47 | Map-reduce model 48 | - split the elements into chunks - Splitter 49 | - operation 50 | - recombine - Combiner 51 | */ 52 | 53 | // map, flatMap, filter, foreach, reduce, fold 54 | 55 | // fold, reduce with non-associative operators 56 | println(List(1,2,3).reduce(_ - _)) 57 | println(List(1,2,3).par.reduce(_ - _)) 58 | 59 | // synchronization 60 | var sum = 0 61 | List(1,2,3).par.foreach(sum += _) 62 | println(sum) // race conditions! 63 | 64 | // configuring 65 | aParVector.tasksupport = new ForkJoinTaskSupport(new ForkJoinPool(2)) 66 | /* 67 | alternatives 68 | - ThreadPoolTaskSupport - deprecated 69 | - ExecutionContextTaskSupport(EC) 70 | */ 71 | 72 | // aParVector.tasksupport = new TaskSupport { 73 | // override def execute[R, Tp](fjtask: Task[R, Tp]): () => R = ??? 74 | // 75 | // override def executeAndWaitResult[R, Tp](task: Task[R, Tp]): R = ??? 76 | // 77 | // override def parallelismLevel: Int = ??? 78 | // 79 | // override val environment: AnyRef = ??? 80 | // } 81 | 82 | // 2 - atomic ops and references 83 | 84 | val atomic = new AtomicReference[Int](2) 85 | 86 | val currentValue = atomic.get() // thread-safe read 87 | atomic.set(4) // thread-safe write 88 | 89 | atomic.getAndSet(5) // thread safe combo 90 | 91 | atomic.compareAndSet(38, 56) 92 | // if the value is 38, then set to 56 93 | // reference equality 94 | 95 | atomic.updateAndGet(_ + 1) // thread-safe function run 96 | atomic.getAndUpdate(_ + 1) 97 | 98 | atomic.accumulateAndGet(12, _ + _) // thread-safe accumulation 99 | atomic.getAndAccumulate(12, _ + _) 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/lectures/part3concurrency/ThreadCommunication.scala: -------------------------------------------------------------------------------- 1 | package lectures.part3concurrency 2 | 3 | import scala.collection.mutable 4 | import scala.util.Random 5 | 6 | /** 7 | * Created by Daniel. 8 | */ 9 | object ThreadCommunication extends App { 10 | 11 | /* 12 | the producer-consumer problem 13 | 14 | producer -> [ ? ] -> consumer 15 | */ 16 | class SimpleContainer { 17 | private var value: Int = 0 18 | 19 | def isEmpty: Boolean = value == 0 20 | def set(newValue: Int) = value = newValue 21 | def get = { 22 | val result = value 23 | value = 0 24 | result 25 | } 26 | } 27 | 28 | def naiveProdCons(): Unit = { 29 | val container = new SimpleContainer 30 | 31 | val consumer = new Thread(() => { 32 | println("[consumer] waiting...") 33 | while(container.isEmpty) { 34 | println("[consumer] actively waiting...") 35 | } 36 | 37 | println("[consumer] I have consumed " + container.get) 38 | }) 39 | 40 | val producer = new Thread(() => { 41 | println("[producer] computing...") 42 | Thread.sleep(500) 43 | val value = 42 44 | println("[producer] I have produced, after long work, the value " + value) 45 | container.set(value) 46 | }) 47 | 48 | consumer.start() 49 | producer.start() 50 | } 51 | 52 | // naiveProdCons() 53 | 54 | // wait and notify 55 | def smartProdCons(): Unit = { 56 | val container = new SimpleContainer 57 | 58 | val consumer = new Thread(() => { 59 | println("[consumer] waiting...") 60 | container.synchronized { 61 | container.wait() 62 | } 63 | 64 | // container must have some value 65 | println("[consumer] I have consumed " + container.get) 66 | }) 67 | 68 | val producer = new Thread(() => { 69 | println("[producer] Hard at work...") 70 | Thread.sleep(2000) 71 | val value = 42 72 | 73 | container.synchronized { 74 | println("[producer] I'm producing " + value) 75 | container.set(value) 76 | container.notify() 77 | } 78 | }) 79 | 80 | consumer.start() 81 | producer.start() 82 | } 83 | 84 | // smartProdCons() 85 | 86 | /* 87 | producer -> [ ? ? ? ] -> consumer 88 | */ 89 | 90 | def prodConsLargeBuffer(): Unit = { 91 | val buffer: mutable.Queue[Int] = new mutable.Queue[Int] 92 | val capacity = 3 93 | 94 | val consumer = new Thread(() => { 95 | val random = new Random() 96 | 97 | while(true) { 98 | buffer.synchronized { 99 | if (buffer.isEmpty) { 100 | println("[consumer] buffer empty, waiting...") 101 | buffer.wait() 102 | } 103 | 104 | // there must be at least ONE value in the buffer 105 | val x = buffer.dequeue() 106 | println("[consumer] consumed " + x) 107 | 108 | // hey producer, there's empty space available, are you lazy?! 109 | buffer.notify() 110 | } 111 | 112 | Thread.sleep(random.nextInt(250)) 113 | } 114 | }) 115 | 116 | val producer = new Thread(() => { 117 | val random = new Random() 118 | var i = 0 119 | 120 | while(true) { 121 | buffer.synchronized { 122 | if (buffer.size == capacity) { 123 | println("[producer] buffer is full, waiting...") 124 | buffer.wait() 125 | } 126 | 127 | // there must be at least ONE EMPTY SPACE in the buffer 128 | println("[producer] producing " + i) 129 | buffer.enqueue(i) 130 | 131 | // hey consumer, new food for you! 132 | buffer.notify() 133 | 134 | i += 1 135 | } 136 | 137 | Thread.sleep(random.nextInt(500)) 138 | } 139 | }) 140 | 141 | consumer.start() 142 | producer.start() 143 | } 144 | 145 | // prodConsLargeBuffer() 146 | 147 | /* 148 | Prod-cons, level 3 149 | 150 | producer1 -> [ ? ? ? ] -> consumer1 151 | producer2 -----^ ^---- consumer2 152 | */ 153 | 154 | 155 | class Consumer(id: Int, buffer: mutable.Queue[Int]) extends Thread { 156 | override def run(): Unit = { 157 | val random = new Random() 158 | 159 | while(true) { 160 | buffer.synchronized { 161 | /* 162 | producer produces value, two Cons are waiting 163 | notifies ONE consumer, notifies on buffer 164 | notifies the other consumer 165 | 166 | */ 167 | while (buffer.isEmpty) { 168 | println(s"[consumer $id] buffer empty, waiting...") 169 | buffer.wait() 170 | } 171 | 172 | // there must be at least ONE value in the buffer 173 | val x = buffer.dequeue() // OOps.! 174 | println(s"[consumer $id] consumed " + x) 175 | 176 | buffer.notifyAll() 177 | } 178 | 179 | Thread.sleep(random.nextInt(250)) 180 | } 181 | } 182 | } 183 | 184 | class Producer(id: Int, buffer: mutable.Queue[Int], capacity: Int) extends Thread { 185 | override def run(): Unit = { 186 | val random = new Random() 187 | var i = 0 188 | 189 | while(true) { 190 | buffer.synchronized { 191 | while (buffer.size == capacity) { 192 | println(s"[producer $id] buffer is full, waiting...") 193 | buffer.wait() 194 | } 195 | 196 | // there must be at least ONE EMPTY SPACE in the buffer 197 | println(s"[producer $id] producing " + i) 198 | buffer.enqueue(i) 199 | 200 | buffer.notifyAll() 201 | 202 | i += 1 203 | } 204 | 205 | Thread.sleep(random.nextInt(500)) 206 | } 207 | } 208 | } 209 | 210 | def multiProdCons(nConsumers: Int, nProducers: Int): Unit = { 211 | val buffer: mutable.Queue[Int] = new mutable.Queue[Int] 212 | val capacity = 20 213 | 214 | (1 to nConsumers).foreach(i => new Consumer(i, buffer).start()) 215 | (1 to nProducers).foreach(i => new Producer(i, buffer, capacity).start()) 216 | } 217 | 218 | // multiProdCons(3, 6) 219 | 220 | /* 221 | Exercises. 222 | 1) think of an example where notifyALL acts in a different way than notify? 223 | 2) create a deadlock 224 | 3) create a livelock 225 | */ 226 | 227 | // notifyall 228 | def testNotifyAll(): Unit = { 229 | val bell = new Object 230 | 231 | (1 to 10).foreach(i => new Thread(() => { 232 | bell.synchronized { 233 | println(s"[thread $i] waiting...") 234 | bell.wait() 235 | println(s"[thread $i] hooray!") 236 | } 237 | }).start()) 238 | 239 | new Thread(() => { 240 | Thread.sleep(2000) 241 | println("[announcer] Rock'n roll!") 242 | bell.synchronized { 243 | bell.notifyAll() 244 | } 245 | }).start() 246 | } 247 | 248 | testNotifyAll() 249 | 250 | // 2 - deadlock 251 | case class Friend(name: String) { 252 | def bow(other: Friend) = { 253 | this.synchronized { 254 | println(s"$this: I am bowing to my friend $other") 255 | other.rise(this) 256 | println(s"$this: my friend $other has risen") 257 | } 258 | } 259 | 260 | def rise(other: Friend) = { 261 | this.synchronized { 262 | println(s"$this: I am rising to my friend $other") 263 | } 264 | } 265 | 266 | var side = "right" 267 | def switchSide(): Unit = { 268 | if (side == "right") side = "left" 269 | else side = "right" 270 | } 271 | 272 | def pass(other: Friend): Unit = { 273 | while (this.side == other.side) { 274 | println(s"$this: Oh, but please, $other, feel free to pass...") 275 | switchSide() 276 | Thread.sleep(1000) 277 | } 278 | } 279 | } 280 | 281 | val sam = Friend("Sam") 282 | val pierre = Friend("Pierre") 283 | 284 | // new Thread(() => sam.bow(pierre)).start() // sam's lock, | then pierre's lock 285 | // new Thread(() => pierre.bow(sam)).start() // pierre's lock | then sam's lock 286 | 287 | // 3 - livelock 288 | // new Thread(() => sam.pass(pierre)).start() 289 | // new Thread(() => pierre.pass(sam)).start() 290 | } 291 | -------------------------------------------------------------------------------- /src/lectures/part4implicits/ImplicitsIntro.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object ImplicitsIntro extends App { 7 | 8 | val pair = "Daniel" -> "555" 9 | val intPair = 1 -> 2 10 | 11 | case class Person(name: String) { 12 | def greet = s"Hi, my name is $name!" 13 | } 14 | 15 | implicit def fromStringToPerson(str: String): Person = Person(str) 16 | 17 | println("Peter".greet) // println(fromStringToPerson("Peter").greet) 18 | 19 | // class A { 20 | // def greet: Int = 2 21 | // } 22 | // implicit def fromStringToA(str: String): A = new A 23 | 24 | // implicit parameters 25 | def increment(x: Int)(implicit amount: Int) = x + amount 26 | implicit val defaultAmount = 10 27 | 28 | increment(2) 29 | // NOT default args 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/lectures/part4implicits/JSONSerialization.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | import java.util.Date 4 | 5 | import lectures.part4implicits.JSONSerialization.JSONNumber 6 | 7 | /** 8 | * Created by Daniel. 9 | */ 10 | object JSONSerialization extends App { 11 | 12 | /* 13 | Users, posts, feeds 14 | Serialize to JSON 15 | */ 16 | 17 | case class User(name: String, age: Int, email: String) 18 | case class Post(content: String, createdAt: Date) 19 | case class Feed(user: User, posts: List[Post]) 20 | 21 | /* 22 | 1 - intermediate data types: Int, String, List, Date 23 | 2 - type classes for conversion to intermediate data types 24 | 3 - serialize to JSON 25 | */ 26 | 27 | sealed trait JSONValue { // intermediate data type 28 | def stringify: String 29 | } 30 | 31 | final case class JSONString(value: String) extends JSONValue { 32 | def stringify: String = 33 | "\"" + value + "\"" 34 | } 35 | 36 | final case class JSONNumber(value: Int) extends JSONValue { 37 | def stringify: String = value.toString 38 | } 39 | 40 | final case class JSONArray(values: List[JSONValue]) extends JSONValue { 41 | def stringify: String = values.map(_.stringify).mkString("[", ",", "]") 42 | } 43 | 44 | final case class JSONObject(values: Map[String, JSONValue]) extends JSONValue { 45 | /* 46 | { 47 | name: "John" 48 | age: 22 49 | friends: [ ... ] 50 | latestPost: { 51 | content: "Scala Rocks" 52 | date: ... 53 | } 54 | } 55 | */ 56 | def stringify: String = values.map { 57 | case (key, value) => "\"" + key + "\":" + value.stringify 58 | } 59 | .mkString("{", ",", "}") 60 | 61 | } 62 | 63 | val data = JSONObject(Map( 64 | "user" -> JSONString("Daniel"), 65 | "posts" -> JSONArray(List( 66 | JSONString("Scala Rocks!"), 67 | JSONNumber(453) 68 | )) 69 | )) 70 | 71 | println(data.stringify) 72 | 73 | // type class 74 | /* 75 | 1 - type class 76 | 2 - type class instances (implicit) 77 | 3 - pimp library to use type class instances 78 | */ 79 | 80 | // 2.1 81 | trait JSONConverter[T] { 82 | def convert(value: T): JSONValue 83 | } 84 | 85 | // 2.3 conversion 86 | 87 | implicit class JSONOps[T](value: T) { 88 | def toJSON(implicit converter: JSONConverter[T]): JSONValue = 89 | converter.convert(value) 90 | } 91 | 92 | // 2.2 93 | 94 | // existing data types 95 | implicit object StringConverter extends JSONConverter[String] { 96 | def convert(value: String): JSONValue = JSONString(value) 97 | } 98 | 99 | implicit object NumberConverter extends JSONConverter[Int] { 100 | def convert(value: Int): JSONValue = JSONNumber(value) 101 | } 102 | 103 | // custom data types 104 | implicit object UserConverter extends JSONConverter[User] { 105 | def convert(user: User): JSONValue = JSONObject(Map( 106 | "name" -> JSONString(user.name), 107 | "age" -> JSONNumber(user.age), 108 | "email" -> JSONString(user.email) 109 | )) 110 | } 111 | 112 | implicit object PostConverter extends JSONConverter[Post] { 113 | def convert(post: Post): JSONValue = JSONObject(Map( 114 | "content" -> JSONString(post.content), 115 | "created:" -> JSONString(post.createdAt.toString) 116 | )) 117 | } 118 | 119 | implicit object FeedConverter extends JSONConverter[Feed] { 120 | def convert(feed: Feed): JSONValue = JSONObject(Map( 121 | "user" -> feed.user.toJSON, 122 | "posts" -> JSONArray(feed.posts.map(_.toJSON)) 123 | )) 124 | } 125 | 126 | // call stringify on result 127 | val now = new Date(System.currentTimeMillis()) 128 | val john = User("John", 34, "john@rockthejvm.com") 129 | val feed = Feed(john, List( 130 | Post("hello", now), 131 | Post("look at this cute puppy", now) 132 | )) 133 | 134 | println(feed.toJSON.stringify) 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/lectures/part4implicits/MagnetPattern.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | import scala.concurrent.Future 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | /** 7 | * Created by Daniel. 8 | */ 9 | object MagnetPattern extends App { 10 | 11 | // method overloading 12 | 13 | class P2PRequest 14 | class P2PResponse 15 | class Serializer[T] 16 | 17 | 18 | trait Actor { 19 | def receive(statusCode: Int): Int 20 | def receive(request: P2PRequest): Int 21 | def receive(response: P2PResponse): Int 22 | def receive[T : Serializer](message: T): Int 23 | def receive[T : Serializer](message: T, statusCode: Int): Int 24 | def receive(future: Future[P2PRequest]): Int 25 | // def receive(future: Future[P2PResponse]): Int 26 | // lots of overloads 27 | } 28 | 29 | /* 30 | 1 - type erasure 31 | 2 - lifting doesn't work for all overloads 32 | 33 | val receiveFV = receive _ // ?! 34 | 35 | 3 - code duplication 36 | 4 - type inferrence and default args 37 | 38 | actor.receive(?!) 39 | */ 40 | 41 | trait MessageMagnet[Result] { 42 | def apply(): Result 43 | } 44 | 45 | def receive[R](magnet: MessageMagnet[R]): R = magnet() 46 | 47 | implicit class FromP2PRequest(request: P2PRequest) extends MessageMagnet[Int] { 48 | def apply(): Int = { 49 | // logic for handling a P2PRequest 50 | println("Handling P2P request") 51 | 42 52 | } 53 | } 54 | 55 | implicit class FromP2PResponse(response: P2PResponse) extends MessageMagnet[Int] { 56 | def apply(): Int = { 57 | // logic for handling a P2PResponse 58 | println("Handling P2P response") 59 | 24 60 | } 61 | } 62 | 63 | receive(new P2PRequest) 64 | receive(new P2PResponse) 65 | 66 | // 1 - no more type erasure problems! 67 | implicit class FromResponseFuture(future: Future[P2PResponse]) extends MessageMagnet[Int] { 68 | override def apply(): Int = 2 69 | } 70 | 71 | implicit class FromRequestFuture(future: Future[P2PRequest]) extends MessageMagnet[Int] { 72 | override def apply(): Int = 3 73 | } 74 | 75 | println(receive(Future(new P2PRequest))) 76 | println(receive(Future(new P2PResponse))) 77 | 78 | // 2 - lifting works 79 | trait MathLib { 80 | def add1(x: Int): Int = x + 1 81 | def add1(s: String): Int = s.toInt + 1 82 | // add1 overloads 83 | } 84 | 85 | // "magnetize" 86 | trait AddMagnet { 87 | def apply(): Int 88 | } 89 | 90 | def add1(magnet: AddMagnet): Int = magnet() 91 | 92 | implicit class AddInt(x: Int) extends AddMagnet { 93 | override def apply(): Int = x + 1 94 | } 95 | 96 | implicit class AddString(s: String) extends AddMagnet { 97 | override def apply(): Int = s.toInt + 1 98 | } 99 | 100 | val addFV = add1 _ 101 | println(addFV(1)) 102 | println(addFV("3")) 103 | 104 | // val receiveFV = receive _ 105 | // receiveFV(new P2PResponse) 106 | 107 | /* 108 | Drawbacks 109 | 1 - verbose 110 | 2 - harder to read 111 | 3 - you can't name or place default arguments 112 | 4 - call by name doesn't work correctly 113 | (exercise: prove it!) (hint: side effects) 114 | */ 115 | 116 | class Handler { 117 | def handle(s: => String) = { 118 | println(s) 119 | println(s) 120 | } 121 | // other overloads 122 | } 123 | 124 | trait HandleMagnet { 125 | def apply(): Unit 126 | } 127 | 128 | def handle(magnet: HandleMagnet) = magnet() 129 | 130 | implicit class StringHandle(s: => String) extends HandleMagnet { 131 | override def apply(): Unit = { 132 | println(s) 133 | println(s) 134 | } 135 | } 136 | 137 | def sideEffectMethod(): String = { 138 | println("Hello, Scala") 139 | "hahaha" 140 | } 141 | 142 | // handle(sideEffectMethod()) 143 | handle { 144 | println("Hello, Scala") 145 | new StringHandle("magnet") 146 | } 147 | // careful! 148 | } 149 | -------------------------------------------------------------------------------- /src/lectures/part4implicits/MyTypeClassTemplate.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | // TYPE CLASS 4 | trait MyTypeClassTemplate[T] { 5 | def action(value: T): String 6 | } 7 | 8 | object MyTypeClassTemplate { 9 | def apply[T](implicit instance: MyTypeClassTemplate[T]) = instance 10 | } -------------------------------------------------------------------------------- /src/lectures/part4implicits/OrganizingImplicits.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object OrganizingImplicits extends App { 7 | 8 | implicit def reverseOrdering: Ordering[Int] = Ordering.fromLessThan(_ > _) 9 | // implicit val normalOrdering: Ordering[Int] = Ordering.fromLessThan(_ < _) 10 | 11 | println(List(1,4,5,3,2).sorted) 12 | 13 | // scala.Predef 14 | 15 | /* 16 | Implicits (used as implicit parameters): 17 | - val/var 18 | - object 19 | - accessor methods = defs with no parentheses 20 | */ 21 | 22 | // Exercise 23 | case class Person(name: String, age: Int) 24 | 25 | val persons = List( 26 | Person("Steve", 30), 27 | Person("Amy", 22), 28 | Person("John", 66) 29 | ) 30 | 31 | // object Person { 32 | // implicit val alphabeticOrdering: Ordering[Person] = Ordering.fromLessThan((a, b) => a.name.compareTo(b.name) < 0) 33 | // } 34 | // implicit val ageOrdering: Ordering[Person] = Ordering.fromLessThan((a, b) => a.age < b.age) 35 | // println(persons.sorted) 36 | 37 | /* 38 | Implicit scope 39 | - normal scope = LOCAL SCOPE 40 | - imported scope 41 | - companions of all types involved in the method signature 42 | - List 43 | - Ordering 44 | - all the types involved = A or any supertype 45 | */ 46 | // def sorted[B >: A](implicit ord: Ordering[B]): List[B] 47 | 48 | object AlphabeticNameOrdering { 49 | implicit val alphabeticOrdering: Ordering[Person] = Ordering.fromLessThan((a, b) => a.name.compareTo(b.name) < 0) 50 | } 51 | 52 | object AgeOrdering { 53 | implicit val ageOrdering: Ordering[Person] = Ordering.fromLessThan((a, b) => a.age < b.age) 54 | } 55 | 56 | import AgeOrdering._ 57 | println(persons.sorted) 58 | 59 | /* 60 | Exercise. 61 | 62 | - totalPrice = most used (50%) 63 | - by unit count = 25% 64 | - by unit price = 25% 65 | 66 | */ 67 | case class Purchase(nUnits: Int, unitPrice: Double) 68 | object Purchase { 69 | implicit val totalPriceOrdering: Ordering[Purchase] = Ordering.fromLessThan((a,b) => a.nUnits * a.unitPrice < b.nUnits * b.unitPrice) 70 | } 71 | 72 | object UnitCountOrdering { 73 | implicit val unitCountOrdering: Ordering[Purchase] = Ordering.fromLessThan(_.nUnits < _.nUnits) 74 | } 75 | 76 | object UnitPriceOrdering { 77 | implicit val unitPriceOrdering: Ordering[Purchase] = Ordering.fromLessThan(_.unitPrice < _.unitPrice) 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/lectures/part4implicits/PimpMyLibrary.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object PimpMyLibrary extends App { 7 | 8 | // 2.isPrime 9 | 10 | implicit class RichInt(val value: Int) extends AnyVal { 11 | def isEven: Boolean = value % 2 == 0 12 | def sqrt: Double = Math.sqrt(value) 13 | 14 | def times(function: () => Unit): Unit = { 15 | def timesAux(n: Int): Unit = 16 | if (n <= 0) () 17 | else { 18 | function() 19 | timesAux(n - 1) 20 | } 21 | 22 | timesAux(value) 23 | } 24 | 25 | def *[T](list: List[T]): List[T] = { 26 | def concatenate(n: Int): List[T] = 27 | if (n <= 0) List() 28 | else concatenate(n - 1) ++ list 29 | 30 | concatenate(value) 31 | } 32 | 33 | } 34 | 35 | implicit class RicherInt(richInt: RichInt) { 36 | def isOdd: Boolean = richInt.value % 2 != 0 37 | } 38 | 39 | new RichInt(42).sqrt 40 | 41 | 42.isEven // new RichInt(42).isEven 42 | // type enrichment = pimping 43 | 44 | 1 to 10 45 | 46 | import scala.concurrent.duration._ 47 | 3.seconds 48 | 49 | // compiler doesn't do multiple implicit searches. 50 | // 42.isOdd 51 | 52 | /* 53 | Enrich the String class 54 | - asInt 55 | - encrypt 56 | "John" -> Lqjp 57 | 58 | Keep enriching the Int class 59 | - times(function) 60 | 3.times(() => ...) 61 | - * 62 | 3 * List(1,2) => List(1,2,1,2,1,2) 63 | */ 64 | 65 | implicit class RichString(string: String) { 66 | def asInt: Int = Integer.valueOf(string) // java.lang.Integer -> Int 67 | def encrypt(cypherDistance: Int): String = string.map(c => (c + cypherDistance).asInstanceOf[Char]) 68 | } 69 | 70 | println("3".asInt + 4) 71 | println("John".encrypt(2)) 72 | 73 | 3.times(() => println("Scala Rocks!")) 74 | println(4 * List(1,2)) 75 | 76 | // "3" / 4 77 | implicit def stringToInt(string: String): Int = Integer.valueOf(string) 78 | println("6" / 2) // stringToInt("6") / 2 79 | 80 | // equivalent: implicit class RichAltInt(value: Int) 81 | class RichAltInt(value: Int) 82 | implicit def enrich(value: Int): RichAltInt = new RichAltInt(value) 83 | 84 | // danger zone 85 | implicit def intToBoolean(i: Int): Boolean = i == 1 86 | 87 | /* 88 | if (n) do something 89 | else do something else 90 | */ 91 | 92 | val aConditionedValue = if (3) "OK" else "Something wrong" 93 | println(aConditionedValue) 94 | } 95 | -------------------------------------------------------------------------------- /src/lectures/part4implicits/ScalaJavaConversions.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | import java.{util => ju} 4 | /** 5 | * Created by Daniel. 6 | */ 7 | object ScalaJavaConversions extends App { 8 | 9 | import collection.JavaConverters._ 10 | 11 | import scala.jdk.CollectionConverters._ 12 | 13 | val javaSet: ju.Set[Int] = new ju.HashSet[Int]() 14 | (1 to 5).foreach(javaSet.add) 15 | println(javaSet) 16 | 17 | val scalaSet = javaSet.asScala 18 | 19 | /* 20 | Iterator 21 | Iterable 22 | ju.List - collection.mutable.Buffer 23 | ju.Set - collection.mutable.Set 24 | ju.Map - collection.mutable.Map 25 | 26 | */ 27 | 28 | import collection.mutable._ 29 | val numbersBuffer = ArrayBuffer[Int](1, 2, 3) 30 | val juNumbersBuffer = numbersBuffer.asJava 31 | 32 | println(juNumbersBuffer.asScala eq numbersBuffer) 33 | 34 | val numbers = List(1,2,3) 35 | val juNumbers = numbers.asJava 36 | val backToScala = juNumbers.asScala 37 | println(backToScala eq numbers) // false 38 | println(backToScala == numbers) // true 39 | 40 | // juNumbers.add(7) 41 | 42 | /* 43 | Exercise 44 | create a Scala-Java Optional-Option 45 | .asScala 46 | */ 47 | class ToScala[T](value: => T) { 48 | def asScala: T = value 49 | } 50 | 51 | implicit def asScalaOptional[T](o: ju.Optional[T]): ToScala[Option[T]] = new ToScala[Option[T]]( 52 | if (o.isPresent) Some(o.get) else None 53 | ) 54 | 55 | val juOptional: ju.Optional[Int] = ju.Optional.of(2) 56 | val scalaOption = juOptional.asScala 57 | println(scalaOption) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/lectures/part4implicits/TypeClasses.scala: -------------------------------------------------------------------------------- 1 | package lectures.part4implicits 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object TypeClasses extends App { 7 | 8 | trait HTMLWritable { 9 | def toHtml: String 10 | } 11 | 12 | case class User(name: String, age: Int, email: String) extends HTMLWritable { 13 | override def toHtml: String = s"
$name ($age yo)
" 14 | } 15 | 16 | User("John", 32, "john@rockthejvm.com").toHtml 17 | /* 18 | 1 - for the types WE write 19 | 2 - ONE implementation out of quite a number 20 | */ 21 | 22 | // option 2 - pattern matching 23 | object HTMLSerializerPM { 24 | def serializeToHtml(value: Any) = value match { 25 | case User(n, a, e) => 26 | case _ => 27 | } 28 | } 29 | 30 | /* 31 | 1 - lost type safety 32 | 2 - need to modify the code every time 33 | 3 - still ONE implementation 34 | */ 35 | 36 | trait HTMLSerializer[T] { 37 | def serialize(value: T): String 38 | } 39 | 40 | implicit object UserSerializer extends HTMLSerializer[User] { 41 | def serialize(user: User): String = s"
${user.name} (${user.age} yo)
" 42 | } 43 | 44 | val john = User("John", 32, "john@rockthejvm.com") 45 | println(UserSerializer.serialize(john)) 46 | 47 | // 1 - we can define serializers for other types 48 | import java.util.Date 49 | object DateSerializer extends HTMLSerializer[Date] { 50 | override def serialize(date: Date): String = s"
${date.toString()}
" 51 | } 52 | 53 | // 2 - we can define MULTIPLE serializers 54 | object PartialUserSerializer extends HTMLSerializer[User] { 55 | def serialize(user: User): String = s"
${user.name}
" 56 | } 57 | 58 | // part 2 59 | object HTMLSerializer { 60 | def serialize[T](value: T)(implicit serializer: HTMLSerializer[T]): String = 61 | serializer.serialize(value) 62 | 63 | def apply[T](implicit serializer: HTMLSerializer[T]) = serializer 64 | } 65 | 66 | implicit object IntSerializer extends HTMLSerializer[Int] { 67 | override def serialize(value: Int): String = s"
$value
" 68 | } 69 | 70 | println(HTMLSerializer.serialize(42)) 71 | println(HTMLSerializer.serialize(john)) 72 | 73 | // access to the entire type class interface 74 | println(HTMLSerializer[User].serialize(john)) 75 | 76 | 77 | // part 3 78 | implicit class HTMLEnrichment[T](value: T) { 79 | def toHTML(implicit serializer: HTMLSerializer[T]): String = serializer.serialize(value) 80 | } 81 | 82 | println(john.toHTML) // println(new HTMLEnrichment[User](john).toHTML(UserSerializer)) 83 | // COOL! 84 | /* 85 | - extend to new types 86 | - choose implementation 87 | - super expressive! 88 | */ 89 | 90 | println(2.toHTML) 91 | println(john.toHTML(PartialUserSerializer)) 92 | 93 | /* 94 | - type class itself --- HTMLSerializer[T] { .. } 95 | - type class instances (some of which are implicit) --- UserSerializer, IntSerializer 96 | - conversion with implicit classes --- HTMLEnrichment 97 | */ 98 | 99 | // context bounds 100 | def htmlBoilerplate[T](content: T)(implicit serializer: HTMLSerializer[T]): String = 101 | s" ${content.toHTML(serializer)}" 102 | 103 | def htmlSugar[T : HTMLSerializer](content: T): String = { 104 | val serializer = implicitly[HTMLSerializer[T]] 105 | // use serializer 106 | s" ${content.toHTML(serializer)}" 107 | } 108 | 109 | // implicitly 110 | case class Permissions(mask: String) 111 | object Permissions { 112 | implicit val defaultPermissions: Permissions = Permissions("0744") 113 | } 114 | 115 | // in some other part of the code 116 | val standardPerms = implicitly[Permissions] 117 | 118 | 119 | } 120 | 121 | -------------------------------------------------------------------------------- /src/lectures/part5ts/FBoundedPolymorphism.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object FBoundedPolymorphism extends App { 7 | 8 | // trait Animal { 9 | // def breed: List[Animal] 10 | // } 11 | // 12 | // class Cat extends Animal { 13 | // override def breed: List[Animal] = ??? // List[Cat] !! 14 | // } 15 | // 16 | // class Dog extends Animal { 17 | // override def breed: List[Animal] = ??? // List[Dog] !! 18 | // } 19 | 20 | // Solution 1 - naive 21 | 22 | // trait Animal { 23 | // def breed: List[Animal] 24 | // } 25 | // 26 | // class Cat extends Animal { 27 | // override def breed: List[Cat] = ??? // List[Cat] !! 28 | // } 29 | // 30 | // class Dog extends Animal { 31 | // override def breed: List[Cat] = ??? // List[Dog] !! 32 | // } 33 | 34 | 35 | // Solution 2 - FBP 36 | 37 | // trait Animal[A <: Animal[A]] { // recursive type: F-Bounded Polymorphism 38 | // def breed: List[Animal[A]] 39 | // } 40 | // 41 | // class Cat extends Animal[Cat] { 42 | // override def breed: List[Animal[Cat]] = ??? // List[Cat] !! 43 | // } 44 | // 45 | // class Dog extends Animal[Dog] { 46 | // override def breed: List[Animal[Dog]] = ??? // List[Dog] !! 47 | // } 48 | // 49 | // trait Entity[E <: Entity[E]] // ORM 50 | // class Person extends Comparable[Person] { // FBP 51 | // override def compareTo(o: Person): Int = ??? 52 | // } 53 | // 54 | // class Crocodile extends Animal[Dog] { 55 | // override def breed: List[Animal[Dog]] = ??? // List[Dog] !! 56 | // } 57 | 58 | // Solution 3 - FBP + self-types 59 | 60 | // trait Animal[A <: Animal[A]] { self: A => 61 | // def breed: List[Animal[A]] 62 | // } 63 | // 64 | // class Cat extends Animal[Cat] { 65 | // override def breed: List[Animal[Cat]] = ??? // List[Cat] !! 66 | // } 67 | // 68 | // class Dog extends Animal[Dog] { 69 | // override def breed: List[Animal[Dog]] = ??? // List[Dog] !! 70 | // } 71 | 72 | // class Crocodile extends Animal[Dog] { 73 | // override def breed: List[Animal[Dog]] = ??? // List[Dog] !! 74 | // } 75 | // 76 | // trait Fish extends Animal[Fish] 77 | // class Shark extends Fish { 78 | // override def breed: List[Animal[Fish]] = List(new Cod) // wrong 79 | // } 80 | // 81 | // class Cod extends Fish { 82 | // override def breed: List[Animal[Fish]] = ??? 83 | // } 84 | 85 | // Exercise 86 | 87 | // Solution 4 type classes! 88 | 89 | // trait Animal 90 | // trait CanBreed[A] { 91 | // def breed(a: A): List[A] 92 | // } 93 | // 94 | // class Dog extends Animal 95 | // object Dog { 96 | // implicit object DogsCanBreed extends CanBreed[Dog] { 97 | // def breed(a: Dog): List[Dog] = List() 98 | // } 99 | // } 100 | // 101 | // implicit class CanBreedOps[A](animal: A) { 102 | // def breed(implicit canBreed: CanBreed[A]): List[A] = 103 | // canBreed.breed(animal) 104 | // } 105 | // 106 | // val dog = new Dog 107 | // dog.breed // List[Dog]!! 108 | // /* 109 | // new CanBreedOps[Dog](dog).breed(Dog.DogsCanBreed) 110 | // implicit value to pass to breed: Dog.DogsCanBreed 111 | // */ 112 | // 113 | // class Cat extends Animal 114 | // object Cat { 115 | // implicit object CatsCanBreed extends CanBreed[Dog] { 116 | // def breed(a: Dog): List[Dog] = List() 117 | // } 118 | // } 119 | // 120 | // val cat = new Cat 121 | // cat.breed 122 | 123 | // Solution #5 124 | 125 | trait Animal[A] { // pure type classes 126 | def breed(a: A): List[A] 127 | } 128 | 129 | class Dog 130 | object Dog { 131 | implicit object DogAnimal extends Animal[Dog] { 132 | override def breed(a: Dog): List[Dog] = List() 133 | } 134 | } 135 | 136 | class Cat 137 | object Cat { 138 | implicit object CatAnimal extends Animal[Dog] { 139 | override def breed(a: Dog): List[Dog] = List() 140 | } 141 | } 142 | 143 | implicit class AnimalOps[A](animal: A) { 144 | def breed(implicit animalTypeClassInstance: Animal[A]): List[A] = 145 | animalTypeClassInstance.breed(animal) 146 | } 147 | 148 | val dog = new Dog 149 | dog.breed 150 | 151 | // val cat = new Cat 152 | // cat.breed 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/lectures/part5ts/HigherKindedTypes.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | import scala.concurrent.Future 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | /** 7 | * Created by Daniel. 8 | */ 9 | object HigherKindedTypes extends App { 10 | 11 | trait AHigherKindedType[F[_]] 12 | 13 | trait MyList[T] { 14 | def flatMap[B](f: T => B): MyList[B] 15 | } 16 | 17 | trait MyOption[T] { 18 | def flatMap[B](f: T => B): MyOption[B] 19 | } 20 | 21 | trait MyFuture[T] { 22 | def flatMap[B](f: T => B): MyFuture[B] 23 | } 24 | 25 | // combine/multiply List(1,2) x List("a", "b") => List(1a, 1b, 2a, 2b) 26 | 27 | // def multiply[A, B](listA: List[A], listB: List[B]): List[(A, B)] = 28 | // for { 29 | // a <- listA 30 | // b <- listB 31 | // } yield (a, b) 32 | // 33 | // def multiply[A, B](listA: Option[A], listB: Option[B]): Option[(A, B)] = 34 | // for { 35 | // a <- listA 36 | // b <- listB 37 | // } yield (a, b) 38 | // 39 | // def multiply[A, B](listA: Future[A], listB: Future[B]): Future[(A, B)] = 40 | // for { 41 | // a <- listA 42 | // b <- listB 43 | // } yield (a, b) 44 | 45 | // use HKT 46 | 47 | trait Monad[F[_], A] { // higher-kinded type class 48 | def flatMap[B](f: A => F[B]): F[B] 49 | def map[B](f: A => B): F[B] 50 | } 51 | 52 | implicit class MonadList[A](list: List[A]) extends Monad[List, A] { 53 | override def flatMap[B](f: A => List[B]): List[B] = list.flatMap(f) 54 | override def map[B](f: A => B): List[B] = list.map(f) 55 | } 56 | 57 | implicit class MonadOption[A](option: Option[A]) extends Monad[Option, A] { 58 | override def flatMap[B](f: A => Option[B]): Option[B] = option.flatMap(f) 59 | override def map[B](f: A => B): Option[B] = option.map(f) 60 | } 61 | 62 | def multiply[F[_], A, B](ma: Monad[F, A], mb: Monad[F, B]): F[(A, B)] = 63 | for { 64 | a <- ma 65 | b <- mb 66 | } yield (a, b) 67 | /* 68 | ma.flatMap(a => mb.map(b => (a,b))) 69 | */ 70 | 71 | 72 | 73 | val monadList = new MonadList(List(1,2,3)) 74 | monadList.flatMap(x => List(x, x + 1)) // List[Int] 75 | // Monad[List, Int] => List[Int] 76 | monadList.map(_ * 2) // List[Int 77 | // Monad[List, Int] => List[Int] 78 | 79 | println(multiply(List(1,2), List("a", "b"))) 80 | println(multiply(Some(2), Some("scala"))) 81 | } 82 | -------------------------------------------------------------------------------- /src/lectures/part5ts/PathDependentTypes.scala: -------------------------------------------------------------------------------- 1 | package advanced.part5ts 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object PathDependentTypes extends App { 7 | 8 | class Outer { 9 | class Inner 10 | object InnerObject 11 | type InnerType 12 | 13 | def print(i: Inner) = println(i) 14 | def printGeneral(i: Outer#Inner) = println(i) 15 | } 16 | 17 | def aMethod: Int = { 18 | class HelperClass 19 | type HelperType = String 20 | 2 21 | } 22 | 23 | // per-instance 24 | val o = new Outer 25 | val inner = new o.Inner // o.Inner is a TYPE 26 | 27 | val oo = new Outer 28 | // val otherInner: oo.Inner = new o.Inner 29 | 30 | o.print(inner) 31 | // oo.print(inner) 32 | 33 | // path-dependent types 34 | 35 | // Outer#Inner 36 | o.printGeneral(inner) 37 | oo.printGeneral(inner) 38 | 39 | /* 40 | Exercise 41 | DB keyed by Int or String, but maybe others 42 | */ 43 | 44 | /* 45 | use path-dependent types 46 | abstract type members and/or type aliases 47 | */ 48 | 49 | trait ItemLike { 50 | type Key 51 | } 52 | 53 | trait Item[K] extends ItemLike { 54 | type Key = K 55 | } 56 | 57 | trait IntItem extends Item[Int] 58 | trait StringItem extends Item[String] 59 | 60 | def get[ItemType <: ItemLike](key: ItemType#Key): ItemType = ??? 61 | 62 | get[IntItem](42) // ok 63 | get[StringItem]("home") // ok 64 | 65 | // get[IntItem]("scala") // not ok 66 | } 67 | -------------------------------------------------------------------------------- /src/lectures/part5ts/Reflection.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | 4 | /** 5 | * Created by Daniel. 6 | */ 7 | object Reflection extends App { 8 | // reflection + macros + quasiquotes => METAPROGRAMMING 9 | 10 | case class Person(name: String) { 11 | def sayMyName(): Unit = println(s"Hi, my name is $name") 12 | } 13 | 14 | // 0 - import 15 | import scala.reflect.runtime.{universe => ru} 16 | 17 | // 1 - MIRROR 18 | val m = ru.runtimeMirror(getClass.getClassLoader) 19 | // 2 - create a class object = "description" 20 | val clazz = m.staticClass("advanced.part5ts.Reflection.Person") // creating a class object by NAME 21 | // 3 - create a reflected mirror = "can DO things" 22 | val cm = m.reflectClass(clazz) 23 | // 4 - get the constructor 24 | val constructor = clazz.primaryConstructor.asMethod 25 | // 5 - reflect the constructor 26 | val constructorMirror = cm.reflectConstructor(constructor) 27 | // 6 - invoke the constructor 28 | val instance = constructorMirror.apply("John") 29 | 30 | println(instance) 31 | 32 | // I have an instance 33 | val p = Person("Mary") // from the wire as a serialized object 34 | // method name computed from somewhere else 35 | val methodName = "sayMyName" 36 | // 1 - mirror 37 | // 2 - reflect the instance 38 | val reflected = m.reflect(p) 39 | // 3 - method symbol 40 | val methodSymbol = ru.typeOf[Person].decl(ru.TermName(methodName)).asMethod 41 | // 4 - reflect the method = can DO things 42 | val method = reflected.reflectMethod(methodSymbol) 43 | // 5 - invoke the method 44 | 45 | method.apply() 46 | 47 | // type erasure 48 | 49 | // pp #1: differentiate types at runtime 50 | val numbers = List(1,2,3) 51 | numbers match { 52 | case listOfStrings: List[String] => println("list of strings") 53 | case listOfNumbers: List[Int] => println("list of numbers") 54 | } 55 | 56 | // pp #2: limitations on overloads 57 | // def processList(list: List[Int]): Int = 43 58 | // def processList(list: List[String]): Int = 45 59 | 60 | // TypeTags 61 | 62 | // 0 - import 63 | import ru._ 64 | 65 | // 1 - creating a type tag "manually" 66 | val ttag = typeTag[Person] 67 | println(ttag.tpe) 68 | 69 | class MyMap[K, V] 70 | 71 | // 2 - pass type tags as implicit parameters 72 | def getTypeArguments[T](value: T)(implicit typeTag: TypeTag[T]) = typeTag.tpe match { 73 | case TypeRef(_, _, typeArguments) => typeArguments 74 | case _ => List() 75 | } 76 | 77 | val myMap = new MyMap[Int, String] 78 | val typeArgs = getTypeArguments(myMap)//(typeTag: TypeTag[MyMap[Int,String]]) 79 | println(typeArgs) 80 | 81 | def isSubtype[A, B](implicit ttagA: TypeTag[A], ttagB: TypeTag[B]): Boolean = { 82 | ttagA.tpe <:< ttagB.tpe 83 | } 84 | 85 | class Animal 86 | class Dog extends Animal 87 | println(isSubtype[Dog, Animal]) 88 | 89 | // I have an instance 90 | 91 | 92 | // 3 - method symbol 93 | val anotherMethodSymbol = typeTag[Person].tpe.decl(ru.TermName(methodName)).asMethod 94 | // 4 - reflect the method = can DO things 95 | val sameMethod = reflected.reflectMethod(anotherMethodSymbol) 96 | // 5 - invoke the method 97 | sameMethod.apply() 98 | } 99 | -------------------------------------------------------------------------------- /src/lectures/part5ts/RockingInheritance.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object RockingInheritance extends App { 7 | 8 | // convenience 9 | trait Writer[T] { 10 | def write(value: T): Unit 11 | } 12 | trait Closeable { 13 | def close(status: Int): Unit 14 | } 15 | trait GenericStream[T] { 16 | // some methods 17 | def foreach(f: T => Unit): Unit 18 | } 19 | 20 | def processStream[T](stream: GenericStream[T] with Writer[T] with Closeable): Unit = { 21 | stream.foreach(println) 22 | stream.close(0) 23 | } 24 | 25 | // diamond problem 26 | 27 | trait Animal { def name: String } 28 | trait Lion extends Animal { override def name: String = "lion" } 29 | trait Tiger extends Animal { override def name: String = "tiger" } 30 | class Mutant extends Lion with Tiger 31 | 32 | val m = new Mutant 33 | println(m.name) 34 | 35 | /* 36 | Mutant 37 | extends Animal with { override def name: String = "lion" } 38 | with { override def name: String = "tiger" } 39 | 40 | LAST OVERRIDE GETS PICKED 41 | */ 42 | 43 | // the super problem + type linearization 44 | 45 | trait Cold { 46 | def print = println("cold") 47 | } 48 | 49 | trait Green extends Cold { 50 | override def print: Unit = { 51 | println("green") 52 | super.print 53 | } 54 | } 55 | 56 | trait Blue extends Cold { 57 | override def print: Unit = { 58 | println("blue") 59 | super.print 60 | } 61 | } 62 | 63 | class Red { 64 | def print = println("red") 65 | } 66 | 67 | class White extends Red with Green with Blue { 68 | override def print: Unit = { 69 | println("white") 70 | super.print 71 | } 72 | } 73 | 74 | val color = new White 75 | color.print 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/lectures/part5ts/SelfTypes.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object SelfTypes extends App { 7 | 8 | // requiring a type to be mixed in 9 | 10 | trait Instrumentalist { 11 | def play(): Unit 12 | } 13 | 14 | trait Singer { this: Instrumentalist => // SELF TYPE whoever implements Singer to implement Instrumentalist 15 | 16 | // rest of the implementation or API 17 | def sing(): Unit 18 | } 19 | 20 | class LeadSinger extends Singer with Instrumentalist { 21 | override def play(): Unit = ??? 22 | override def sing(): Unit = ??? 23 | } 24 | 25 | // class Vocalist extends Singer { 26 | // override def sing(): Unit = ??? 27 | // } 28 | 29 | val jamesHetfield = new Singer with Instrumentalist { 30 | override def play(): Unit = ??? 31 | override def sing(): Unit = ??? 32 | } 33 | 34 | class Guitarist extends Instrumentalist { 35 | override def play(): Unit = println("(guitar solo)") 36 | } 37 | 38 | val ericClapton = new Guitarist with Singer { 39 | override def sing(): Unit = ??? 40 | } 41 | 42 | // self-types vs inheritance 43 | class A 44 | class B extends A // B IS AN A 45 | 46 | trait T 47 | trait S { self: T => } // S REQUIRES a T 48 | 49 | // CAKE PATTERN => "dependency injection" 50 | 51 | // DI 52 | class Component { 53 | // API 54 | } 55 | class ComponentA extends Component 56 | class ComponentB extends Component 57 | class DependentComponent(val component: Component) 58 | 59 | // CAKE PATTERN 60 | trait ScalaComponent { 61 | // API 62 | def action(x: Int): String 63 | } 64 | trait ScalaDependentComponent { self: ScalaComponent => 65 | def dependentAction(x: Int): String = action(x) + " this rocks!" 66 | } 67 | trait ScalaApplication { self: ScalaDependentComponent => } 68 | 69 | // layer 1 - small components 70 | trait Picture extends ScalaComponent 71 | trait Stats extends ScalaComponent 72 | 73 | // layer 2 - compose 74 | trait Profile extends ScalaDependentComponent with Picture 75 | trait Analytics extends ScalaDependentComponent with Stats 76 | 77 | // layer 3 - app 78 | trait AnalyticsApp extends ScalaApplication with Analytics 79 | 80 | 81 | 82 | // cyclical dependencies 83 | 84 | // class X extends Y 85 | // class Y extends X 86 | 87 | trait X { self: Y => } 88 | trait Y { self: X => } 89 | } 90 | -------------------------------------------------------------------------------- /src/lectures/part5ts/StructuralTypes.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | import scala.language.reflectiveCalls 4 | 5 | /** 6 | * Created by Daniel. 7 | */ 8 | object StructuralTypes extends App { 9 | 10 | // structural types 11 | 12 | type JavaCloseable = java.io.Closeable 13 | 14 | class HipsterCloseable { 15 | def close(): Unit = println("yeah yeah I'm closing") 16 | def closeSilently(): Unit = println("not making a sound") 17 | } 18 | 19 | // def closeQuietly(closeable: JavaCloseable OR HipsterCloseable) // ?! 20 | 21 | type UnifiedCloseable = { 22 | def close(): Unit 23 | } // STRUCTURAL TYPE 24 | 25 | def closeQuietly(unifiedCloseable: UnifiedCloseable): Unit = unifiedCloseable.close() 26 | 27 | closeQuietly(new JavaCloseable { 28 | override def close(): Unit = ??? 29 | }) 30 | closeQuietly(new HipsterCloseable) 31 | 32 | 33 | 34 | // TYPE REFINEMENTS 35 | 36 | 37 | type AdvancedCloseable = JavaCloseable { 38 | def closeSilently(): Unit 39 | } 40 | 41 | class AdvancedJavaCloseable extends JavaCloseable { 42 | override def close(): Unit = println("Java closes") 43 | def closeSilently(): Unit = println("Java closes silently") 44 | } 45 | 46 | def closeShh(advCloseable: AdvancedCloseable): Unit = advCloseable.closeSilently() 47 | 48 | closeShh(new AdvancedJavaCloseable) 49 | // closeShh(new HipsterCloseable) 50 | 51 | // using structural types as standalone types 52 | def altClose(closeable: { def close(): Unit }): Unit = closeable.close() 53 | 54 | 55 | // type-checking => duck typing 56 | 57 | type SoundMaker = { 58 | def makeSound(): Unit 59 | } 60 | 61 | class Dog { 62 | def makeSound(): Unit = println("bark!") 63 | } 64 | 65 | class Car { 66 | def makeSound(): Unit = println("vrooom!") 67 | } 68 | 69 | val dog: SoundMaker = new Dog 70 | val car: SoundMaker = new Car 71 | 72 | // static duck typing 73 | 74 | // CAVEAT: based on reflection 75 | 76 | /* 77 | Exercises 78 | */ 79 | 80 | // 1. 81 | trait CBL[+T] { 82 | def head: T 83 | def tail: CBL[T] 84 | } 85 | 86 | class Human { 87 | def head: Brain = new Brain 88 | } 89 | 90 | class Brain { 91 | override def toString: String = "BRAINZ!" 92 | } 93 | 94 | def f[T](somethingWithAHead: { def head: T }): Unit = println(somethingWithAHead.head) 95 | 96 | /* 97 | f is compatible with a CBL and with a Human? Yes. 98 | */ 99 | 100 | case object CBNil extends CBL[Nothing] { 101 | def head: Nothing = ??? 102 | def tail: CBL[Nothing] = ??? 103 | } 104 | case class CBCons[T](override val head: T, override val tail: CBL[T]) extends CBL[T] 105 | 106 | f(CBCons(2, CBNil)) 107 | f(new Human) // ?! T = Brain !! 108 | 109 | // 2. 110 | object HeadEqualizer { 111 | type Headable[T] = { def head: T } 112 | 113 | def ===[T](a: Headable[T], b: Headable[T]): Boolean = a.head == b.head 114 | } 115 | 116 | /* 117 | is compatible with a CBL and with a Human? Yes. 118 | */ 119 | val brainzList = CBCons(new Brain, CBNil) 120 | val stringsList = CBCons("Brainz", CBNil) 121 | 122 | HeadEqualizer.===(brainzList, new Human) 123 | // problem: 124 | HeadEqualizer.===(new Human, stringsList) // not type safe 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/lectures/part5ts/TypeMembers.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object TypeMembers extends App { 7 | 8 | 9 | class Animal 10 | class Dog extends Animal 11 | class Cat extends Animal 12 | 13 | class AnimalCollection { 14 | type AnimalType // abstract type member 15 | type BoundedAnimal <: Animal 16 | type SuperBoundedAnimal >: Dog <: Animal 17 | type AnimalC = Cat 18 | } 19 | 20 | val ac = new AnimalCollection 21 | val dog: ac.AnimalType = ??? 22 | 23 | // val cat: ac.BoundedAnimal = new Cat 24 | 25 | val pup: ac.SuperBoundedAnimal = new Dog 26 | val cat: ac.AnimalC = new Cat 27 | 28 | type CatAlias = Cat 29 | val anotherCat: CatAlias = new Cat 30 | 31 | // alternative to generics 32 | trait MyList { 33 | type T 34 | def add(element: T): MyList 35 | } 36 | 37 | class NonEmptyList(value: Int) extends MyList { 38 | override type T = Int 39 | def add(element: Int): MyList = ??? 40 | } 41 | 42 | // .type 43 | type CatsType = cat.type 44 | val newCat: CatsType = cat 45 | // new CatsType 46 | 47 | /* 48 | Exercise - enforce a type to be applicable to SOME TYPES only 49 | */ 50 | // LOCKED 51 | trait MList { 52 | type A 53 | def head: A 54 | def tail: MList 55 | } 56 | 57 | trait ApplicableToNumbers { 58 | type A <: Number 59 | } 60 | 61 | // NOT OK 62 | // class CustomList(hd: String, tl: CustomList) extends MList with ApplicableToNumbers { 63 | // type A = String 64 | // def head = hd 65 | // def tail = tl 66 | // } 67 | 68 | // OK 69 | class IntList(hd: Integer, tl: IntList) extends MList with ApplicableToNumbers { 70 | type A = Integer 71 | def head = hd 72 | def tail = tl 73 | } 74 | 75 | // Number 76 | // type members and type member constraints (bounds) 77 | } 78 | -------------------------------------------------------------------------------- /src/lectures/part5ts/Variance.scala: -------------------------------------------------------------------------------- 1 | package lectures.part5ts 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | object Variance extends App { 7 | 8 | trait Animal 9 | class Dog extends Animal 10 | class Cat extends Animal 11 | class Crocodile extends Animal 12 | 13 | // what is variance? 14 | // "inheritance" - type substitution of generics 15 | 16 | class Cage[T] 17 | // yes - covariance 18 | class CCage[+T] 19 | val ccage: CCage[Animal] = new CCage[Cat] 20 | 21 | // no - invariance 22 | class ICage[T] 23 | // val icage: ICage[Animal] = new ICage[Cat] 24 | // val x: Int = "hello" 25 | 26 | // hell no - opposite = contravariance 27 | class XCage[-T] 28 | val xcage: XCage[Cat] = new XCage[Animal] 29 | 30 | class InvariantCage[T](val animal: T) // invariant 31 | 32 | // covariant positions 33 | class CovariantCage[+T](val animal: T) // COVARIANT POSITION 34 | 35 | // class ContravariantCage[-T](val animal: T) 36 | /* 37 | val catCage: XCage[Cat] = new XCage[Animal](new Crocodile) 38 | */ 39 | 40 | // class CovariantVariableCage[+T](var animal: T) // types of vars are in CONTRAVARIANT POSITION 41 | /* 42 | val ccage: CCage[Animal] = new CCage[Cat](new Cat) 43 | ccage.animal = new Crocodile 44 | */ 45 | 46 | // class ContravariantVariableCage[-T](var animal: T) // also in COVARIANT POSITION 47 | /* 48 | val catCage: XCage[Cat] = new XCage[Animal](new Crocodile) 49 | */ 50 | class InvariantVariableCage[T](var animal: T) // ok 51 | 52 | // trait AnotherCovariantCage[+T] { 53 | // def addAnimal(animal: T) // CONTRAVARIANT POSITION 54 | // } 55 | /* 56 | val ccage: CCage[Animal] = new CCage[Dog] 57 | ccage.add(new Cat) 58 | */ 59 | 60 | class AnotherContravariantCage[-T] { 61 | def addAnimal(animal: T) = true 62 | } 63 | val acc: AnotherContravariantCage[Cat] = new AnotherContravariantCage[Animal] 64 | acc.addAnimal(new Cat) 65 | class Kitty extends Cat 66 | acc.addAnimal(new Kitty) 67 | 68 | class MyList[+A] { 69 | def add[B >: A](element: B): MyList[B] = new MyList[B] // widening the type 70 | } 71 | 72 | val emptyList = new MyList[Kitty] 73 | val animals = emptyList.add(new Kitty) 74 | val moreAnimals = animals.add(new Cat) 75 | val evenMoreAnimals = moreAnimals.add(new Dog) 76 | 77 | // METHOD ARGUMENTS ARE IN CONTRAVARIANT POSITION. 78 | 79 | // return types 80 | class PetShop[-T] { 81 | // def get(isItaPuppy: Boolean): T // METHOD RETURN TYPES ARE IN COVARIANT POSITION 82 | /* 83 | val catShop = new PetShop[Animal] { 84 | def get(isItaPuppy: Boolean): Animal = new Cat 85 | } 86 | 87 | val dogShop: PetShop[Dog] = catShop 88 | dogShop.get(true) // EVIL CAT! 89 | */ 90 | 91 | def get[S <: T](isItaPuppy: Boolean, defaultAnimal: S): S = defaultAnimal 92 | } 93 | 94 | val shop: PetShop[Dog] = new PetShop[Animal] 95 | // val evilCat = shop.get(true, new Cat) 96 | class TerraNova extends Dog 97 | val bigFurry = shop.get(true, new TerraNova) 98 | 99 | /* 100 | Big rule 101 | - method arguments are in CONTRAVARIANT position 102 | - return types are in COVARIANT position 103 | */ 104 | 105 | /** 106 | * 1. Invariant, covariant, contravariant 107 | * Parking[T](things: List[T]) { 108 | * park(vehicle: T) 109 | * impound(vehicles: List[T]) 110 | * checkVehicles(conditions: String): List[T] 111 | * } 112 | * 113 | * 2. used someone else's API: IList[T] 114 | * 3. Parking = monad! 115 | * - flatMap 116 | */ 117 | class Vehicle 118 | class Bike extends Vehicle 119 | class Car extends Vehicle 120 | class IList[T] 121 | 122 | class IParking[T](vehicles: List[T]) { 123 | def park(vehicle: T): IParking[T] = ??? 124 | def impound(vehicles: List[T]): IParking[T] = ??? 125 | def checkVehicles(conditions: String): List[T] = ??? 126 | 127 | def flatMap[S](f: T => IParking[S]): IParking[S] = ??? 128 | } 129 | 130 | class CParking[+T](vehicles: List[T]) { 131 | def park[S >: T](vehicle: S): CParking[S] = ??? 132 | def impound[S >: T](vehicles: List[S]): CParking[S] = ??? 133 | def checkVehicles(conditions: String): List[T] = ??? 134 | 135 | def flatMap[S](f: T => CParking[S]): CParking[S] = ??? 136 | } 137 | 138 | class CList[-T] 139 | class XParking[-T](vehicles: List[T]) { 140 | def park(vehicle: T): XParking[T] = ??? 141 | def impound[R <: T](vehicles: CList[R]): XParking[R] = ??? 142 | def checkVehicles[S <: T](conditions: String): List[S] = ??? 143 | 144 | def flatMap[R <: T, S](f: Function1[R, XParking[S]]): XParking[S] = ??? 145 | } 146 | 147 | /* 148 | Rule of thumb 149 | - use covariance = COLLECTION OF THINGS 150 | - use contravariance = GROUP OF ACTIONS 151 | */ 152 | 153 | class CParking2[+T](vehicles: IList[T]) { 154 | def park[S >: T](vehicle: S): CParking2[S] = ??? 155 | def impound[S >: T](vehicles: IList[S]): CParking2[S] = ??? 156 | def checkVehicles[S >: T](conditions: String): IList[S] = ??? 157 | } 158 | 159 | class XParking2[-T](vehicles: IList[T]) { 160 | def park(vehicle: T): XParking2[T] = ??? 161 | def impound[S <: T](vehicles: IList[S]): XParking2[S] = ??? 162 | def checkVehicles[S <: T](conditions: String): IList[S] = ??? 163 | } 164 | 165 | // flatMap 166 | } 167 | -------------------------------------------------------------------------------- /src/playground/JavaPlayground.java: -------------------------------------------------------------------------------- 1 | package playground; 2 | 3 | /** 4 | * Created by Daniel. 5 | */ 6 | public class JavaPlayground { 7 | public static void main(String[] args) { 8 | System.out.println("Hello, Java"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/playground/ScalaPlayground.scala: -------------------------------------------------------------------------------- 1 | package playground 2 | 3 | import scala.annotation.tailrec 4 | 5 | /** 6 | * Created by Daniel. 7 | */ 8 | object ScalaPlayground extends App { 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /target/.history3: -------------------------------------------------------------------------------- 1 | 1695548901185:reload 2 | 1695549023073:;set _root_.scala.collection.Seq(historyPath := None,shellPrompt := { _ => "" },SettingKey[_root_.scala.Option[_root_.sbt.File]]("sbtStructureOutputFile") in _root_.sbt.Global := _root_.scala.Some(_root_.sbt.file("/private/var/folders/0_/l801qy2501d6655txswpw8lc0000gn/T/sbt-structure.xml")),SettingKey[_root_.java.lang.String]("sbtStructureOptions") in _root_.sbt.Global := "download, resolveClassifiers");apply -cp "/Users/daniel/Library/Application Support/JetBrains/IdeaIC2023.1/plugins/Scala/repo/org/jetbrains/scala/sbt-structure-extractor_2.12_1.0/2022.3.1/sbt-structure-extractor-2022.3.1.jar" org.jetbrains.sbt.CreateTasks;preferScala2;*/*:dumpStructure 3 | -------------------------------------------------------------------------------- /target/scala-2.13/update/update_cache_2.13/inputs: -------------------------------------------------------------------------------- 1 | -1752903609 -------------------------------------------------------------------------------- /target/streams/_global/_global/csrLogger/_global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] downloaded https://repo1.maven.org/maven2/org/scala-lang/scala-reflect_2.13/2.13.5/scala-reflect_2.13-2.13.5.pom 2 | [debug] downloaded https://repo1.maven.org/maven2/org/scala-lang/scala-reflect_2.13/2.13.5/scala-reflect_2.13-2.13.5.pom.sha1 3 | -------------------------------------------------------------------------------- /target/streams/_global/_global/dumpStructure/_global/streams/out: -------------------------------------------------------------------------------- 1 | [info] Writing structure to /private/var/folders/0_/l801qy2501d6655txswpw8lc0000gn/T/sbt-structure.xml... 2 | [info] Done. 3 | -------------------------------------------------------------------------------- /target/streams/_global/csrConfiguration/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/_global/csrConfiguration/_global/streams/out -------------------------------------------------------------------------------- /target/streams/_global/csrProject/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/_global/csrProject/_global/streams/out -------------------------------------------------------------------------------- /target/streams/_global/dependencyPositions/_global/streams/update_cache_2.13/input_dsp: -------------------------------------------------------------------------------- 1 | -1950826002 -------------------------------------------------------------------------------- /target/streams/_global/dependencyPositions/_global/streams/update_cache_2.13/output_dsp: -------------------------------------------------------------------------------- 1 | {"{\"organization\":\"org.scala-lang\",\"name\":\"scala-library\",\"revision\":\"2.13.5\",\"isChanging\":false,\"isTransitive\":true,\"isForce\":false,\"explicitArtifacts\":[],\"inclusions\":[],\"exclusions\":[],\"extraAttributes\":{},\"crossVersion\":{\"type\":\"Disabled\"}}":{"value":{"$fields":["path","startLine"],"path":"/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/build.sbt","startLine":8},"type":"LinePosition"},"{\"organization\":\"com.novocode\",\"name\":\"junit-interface\",\"revision\":\"0.11\",\"configurations\":\"test\",\"isChanging\":false,\"isTransitive\":true,\"isForce\":false,\"explicitArtifacts\":[],\"inclusions\":[],\"exclusions\":[],\"extraAttributes\":{},\"crossVersion\":{\"type\":\"Disabled\"}}":{"value":{"$fields":["path","startLine"],"path":"/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/build.sbt","startLine":8},"type":"LinePosition"},"{\"organization\":\"org.scala-lang.modules\",\"name\":\"scala-parallel-collections\",\"revision\":\"1.0.4\",\"isChanging\":false,\"isTransitive\":true,\"isForce\":false,\"explicitArtifacts\":[],\"inclusions\":[],\"exclusions\":[],\"extraAttributes\":{},\"crossVersion\":{\"type\":\"Binary\",\"prefix\":\"\",\"suffix\":\"\"}}":{"value":{"$fields":["path","startLine"],"path":"/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/build.sbt","startLine":8},"type":"LinePosition"}} -------------------------------------------------------------------------------- /target/streams/_global/ivyConfiguration/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/_global/ivyConfiguration/_global/streams/out -------------------------------------------------------------------------------- /target/streams/_global/ivySbt/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/_global/ivySbt/_global/streams/out -------------------------------------------------------------------------------- /target/streams/_global/moduleSettings/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/_global/moduleSettings/_global/streams/out -------------------------------------------------------------------------------- /target/streams/_global/projectDescriptors/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/_global/projectDescriptors/_global/streams/out -------------------------------------------------------------------------------- /target/streams/_global/ssExtractDependencies/_global/streams/out: -------------------------------------------------------------------------------- 1 | [error] sbt.librarymanagement.ResolveException: Error downloading org.scala-lang:scala-reflect_2.13:2.13.5 2 | [error] Not found 3 | [error] Not found 4 | [error] not found: /Users/daniel/.ivy2/local/org.scala-lang/scala-reflect_2.13/2.13.5/ivys/ivy.xml 5 | [error] not found: https://repo1.maven.org/maven2/org/scala-lang/scala-reflect_2.13/2.13.5/scala-reflect_2.13-2.13.5.pom 6 | [error] at lmcoursier.CoursierDependencyResolution.unresolvedWarningOrThrow(CoursierDependencyResolution.scala:344) 7 | [error] at lmcoursier.CoursierDependencyResolution.$anonfun$update$38(CoursierDependencyResolution.scala:313) 8 | [error] at scala.util.Either$LeftProjection.map(Either.scala:573) 9 | [error] at lmcoursier.CoursierDependencyResolution.update(CoursierDependencyResolution.scala:313) 10 | [error] at sbt.librarymanagement.DependencyResolution.update(DependencyResolution.scala:60) 11 | [error] at sbt.internal.LibraryManagement$.resolve$1(LibraryManagement.scala:59) 12 | [error] at sbt.internal.LibraryManagement$.$anonfun$cachedUpdate$12(LibraryManagement.scala:133) 13 | [error] at sbt.util.Tracked$.$anonfun$lastOutput$1(Tracked.scala:73) 14 | [error] at sbt.internal.LibraryManagement$.$anonfun$cachedUpdate$20(LibraryManagement.scala:146) 15 | [error] at scala.util.control.Exception$Catch.apply(Exception.scala:228) 16 | [error] at sbt.internal.LibraryManagement$.$anonfun$cachedUpdate$11(LibraryManagement.scala:146) 17 | [error] at sbt.internal.LibraryManagement$.$anonfun$cachedUpdate$11$adapted(LibraryManagement.scala:127) 18 | [error] at sbt.util.Tracked$.$anonfun$inputChangedW$1(Tracked.scala:219) 19 | [error] at sbt.internal.LibraryManagement$.cachedUpdate(LibraryManagement.scala:160) 20 | [error] at sbt.Classpaths$.$anonfun$updateTask0$1(Defaults.scala:3687) 21 | [error] at scala.Function1.$anonfun$compose$1(Function1.scala:49) 22 | [error] at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62) 23 | [error] at sbt.std.Transform$$anon$4.work(Transform.scala:68) 24 | [error] at sbt.Execute.$anonfun$submit$2(Execute.scala:282) 25 | [error] at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23) 26 | [error] at sbt.Execute.work(Execute.scala:291) 27 | [error] at sbt.Execute.$anonfun$submit$1(Execute.scala:282) 28 | [error] at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265) 29 | [error] at sbt.CompletionService$$anon$2.call(CompletionService.scala:64) 30 | [error] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 31 | [error] at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) 32 | [error] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 33 | [error] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) 34 | [error] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) 35 | [error] at java.base/java.lang.Thread.run(Thread.java:833) 36 | [error] (ssExtractDependencies) sbt.librarymanagement.ResolveException: Error downloading org.scala-lang:scala-reflect_2.13:2.13.5 37 | [error] Not found 38 | [error] Not found 39 | [error] not found: /Users/daniel/.ivy2/local/org.scala-lang/scala-reflect_2.13/2.13.5/ivys/ivy.xml 40 | [error] not found: https://repo1.maven.org/maven2/org/scala-lang/scala-reflect_2.13/2.13.5/scala-reflect_2.13-2.13.5.pom 41 | -------------------------------------------------------------------------------- /target/streams/_global/update/_global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] not up to date. inChanged = true, force = false 2 | [debug] Updating ... 3 | [debug] Done updating 4 | -------------------------------------------------------------------------------- /target/streams/_global/updateClassifiers/_global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] not up to date. inChanged = true, force = false 2 | [debug] Updating ProjectRef(uri("file:/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/"), "root")... 3 | [debug] Done updating ProjectRef(uri("file:/Users/daniel/dev/rockthejvm/courses/scala-2-advanced/"), "root") 4 | -------------------------------------------------------------------------------- /target/streams/_global/updateClassifiers/_global/streams/update_cache_2.13/inputs: -------------------------------------------------------------------------------- 1 | -1536732559 -------------------------------------------------------------------------------- /target/streams/compile/externalDependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.5/scala-library-2.13.5.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-parallel-collections_2.13/1.0.4/scala-parallel-collections_2.13-1.0.4.jar 2 | -------------------------------------------------------------------------------- /target/streams/compile/managedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.5/scala-library-2.13.5.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-parallel-collections_2.13/1.0.4/scala-parallel-collections_2.13-1.0.4.jar 2 | -------------------------------------------------------------------------------- /target/streams/compile/scalacOptions/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/compile/scalacOptions/_global/streams/out -------------------------------------------------------------------------------- /target/streams/compile/unmanagedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /target/streams/compile/unmanagedClasspath/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/compile/unmanagedClasspath/_global/streams/out -------------------------------------------------------------------------------- /target/streams/compile/unmanagedJars/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /target/streams/runtime/externalDependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.5/scala-library-2.13.5.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-parallel-collections_2.13/1.0.4/scala-parallel-collections_2.13-1.0.4.jar 2 | -------------------------------------------------------------------------------- /target/streams/runtime/managedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.5/scala-library-2.13.5.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-parallel-collections_2.13/1.0.4/scala-parallel-collections_2.13-1.0.4.jar 2 | -------------------------------------------------------------------------------- /target/streams/runtime/unmanagedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /target/streams/runtime/unmanagedClasspath/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/runtime/unmanagedClasspath/_global/streams/out -------------------------------------------------------------------------------- /target/streams/runtime/unmanagedJars/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /target/streams/test/externalDependencyClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.5/scala-library-2.13.5.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/novocode/junit-interface/0.11/junit-interface-0.11.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-parallel-collections_2.13/1.0.4/scala-parallel-collections_2.13-1.0.4.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar 2 | -------------------------------------------------------------------------------- /target/streams/test/managedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | /Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.5/scala-library-2.13.5.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/novocode/junit-interface/0.11/junit-interface-0.11.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-parallel-collections_2.13/1.0.4/scala-parallel-collections_2.13-1.0.4.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar:/Users/daniel/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar 2 | -------------------------------------------------------------------------------- /target/streams/test/unmanagedClasspath/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /target/streams/test/unmanagedClasspath/_global/streams/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockthejvm/scala-2-advanced/b36e0be212f44b7d1ec7099a65de930707c434b0/target/streams/test/unmanagedClasspath/_global/streams/out -------------------------------------------------------------------------------- /target/streams/test/unmanagedJars/_global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------