{"id":20271719,"url":"https://github.com/rodneyshag/scala","last_synced_at":"2025-03-04T00:05:31.995Z","repository":{"id":123421858,"uuid":"209373439","full_name":"RodneyShag/Scala","owner":"RodneyShag","description":"Scala tutorial","archived":false,"fork":false,"pushed_at":"2020-07-07T23:37:32.000Z","size":32,"stargazers_count":3,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-14T05:49:49.589Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RodneyShag.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-18T18:05:35.000Z","updated_at":"2021-08-24T05:10:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"306a2d42-1149-4e13-aff9-5cd42ef043d6","html_url":"https://github.com/RodneyShag/Scala","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RodneyShag%2FScala","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RodneyShag%2FScala/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RodneyShag%2FScala/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RodneyShag%2FScala/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RodneyShag","download_url":"https://codeload.github.com/RodneyShag/Scala/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241758964,"owners_count":20015251,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T12:39:10.989Z","updated_at":"2025-03-04T00:05:31.971Z","avatar_url":"https://github.com/RodneyShag.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"images/scala_logo.png\"\u003e\n\u003c/p\u003e\n\n- [Introduction](#introduction)\n- [Basics](#basics)\n- [Unified Types](#unified-types)\n- [Classes](#classes)\n- [Tuples](#tuples)\n- [Class composition with Mixins](#class-composition-with-mixins)\n- [Higher Order Functions](#higher-order-functions)\n- [Nested Methods](#nested-methods)\n- [Multiple Parameter Lists (Currying)](#multiple-parameter-lists-currying)\n- [Pattern matching](#pattern-matching)\n- [Singleton objects](#singleton-objects)\n- [Regular Expression Patterns](#regular-expression-patterns)\n- [For Comprehensions](#for-comprehensions)\n- [Generic Classes](#generic-classes)\n- [Variances](#variances)\n- [Upper Type Bounds](#upper-type-bounds)\n- [Lower Type Bounds](#lower-type-bounds)\n- [Inner Classes](#inner-classes)\n- [Self-type](#self-type)\n- [Implicit Parameters](#implicit-parameters)\n- [Polymorphic Methods](#polymorphic-methods)\n- [Operators](#operators)\n- [By-name Parameters](#by-name-parameters)\n- [Default Parameter Values](#default-parameter-values)\n- [Packages and Imports](#packages-and-imports)\n- [More Notes](#more-notes)\n  - [Constructors](#constructors)\n  - [Null, null, Nil, Nothing, None, and Unit in Scala](#null-null-nil-nothing-none-and-unit-in-scala)\n  - [The `return` keyword](#the-return-keyword)\n  - [`lazy val`](#lazy-val)\n- [References](#references)\n\n\nThis repo is a concise summary and _replacement_ of the [Tour of Scala](https://docs.scala-lang.org/tour/tour-of-scala.html) tutorial. Using the hyperlinks below is optional.\n\n\n## [Introduction](https://docs.scala-lang.org/tour/tour-of-scala.html)\n\nScala is both an object-oriented and functional programming language. It is a statically-typed language, but uses _type inference_ so the user is not required to annotate code with redundant type information.\n\nOnline compiler: [Scala Fiddle](https://scalafiddle.io)\n\n\n## [Basics](https://docs.scala-lang.org/tour/basics.html)\n\n#### Values vs. Variables\n\n- `val` is a constant\n- `var` is a variable\n\n```scala\nval x = 2;\nx = 3; // does not compile\n```\n\n```scala\nvar x = 2;\nx = 3; // compiles\n```\n\n#### Declaring type of variable\n\nTypes of values can be inferred, but you can also explicitly state the type:\n\n```scala\nval x: Int = 2\n```\n\n#### Functions\n\n```scala\n(x: Int) =\u003e x + 1                   // anonymous (no-name) function\nval getTheAnswer = () =\u003e 42         // named function (0 parameters)\nval addOne = (x: Int) =\u003e x + 1      // named function (1 parameter)\nval add = (x: Int, y: Int) =\u003e x + y // named function (2 parameters)\n```\n\n#### Blocks \u0026 Returning values\n\nA block evaluates to the last line in the block.\n```scala\nprintln({\n  val x = 1 + 1\n  x + 1\n}) // 3\n```\nFor methods, the `return` statement is not needed, since the value of the last line is returned.\n\n#### Methods\n\n0 parameters\n\n```scala\ndef name: String = System.getProperty(\"user.name\")\n\nprintln(\"Hello, \" + name + \"!\")\n```\n\n1 parameter list\n\n```scala\ndef add(x: Int, y: Int): Int = x + y\n\nprintln(add(1, 2)) // 3\n```\n\n2 parameter lists\n\n```scala\ndef addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier\n\nprintln(addThenMultiply(1, 2)(3)) // 9\n```\n\n#### Classes\n\n`Unit` is like `void` in Java\n\n```scala\nclass Greeter(prefix: String, suffix: String) {\n  def greet(name: String): Unit =\n    println(prefix + name + suffix)\n}\n```\n\n\n```scala\nval greeter = new Greeter(\"Hello, \", \"!\")\ngreeter.greet(\"Scala developer\") // Hello, Scala developer!\n```\n\n#### Case Classes\n\ncase classes are __immutable__ and __compared by value__\n\n```scala\ncase class Point(x: Int, y: Int)\n```\n\nThe `new` keyword is not necessary when creating a Case Class\n\n```scala\nval point = Point(1, 2)\nval anotherPoint = Point(1, 2)\n```\n\n```scala\nif (point == anotherPoint) {\n  println(\"same point\") // this will print\n}\n```\n\n#### Objects\n\nThe object keyword is used to create a singleton. This feature replaces the `static` keyword in Java.\n\n```scala\nobject IdFactory {\n  private var counter = 0\n  def create(): Int = {\n    counter += 1\n    counter\n  }\n}\n```\n\n```scala\nval newId: Int = IdFactory.create()\nprintln(newId) // 1\nval newerId: Int = IdFactory.create()\nprintln(newerId) // 2\n```\n\n#### Traits\n\nTraits are like interfaces in Java\n\n```scala\ntrait Greeter {\n  def greet(name: String): Unit\n}\n```\n\nTraits can have default implementations:\n\n```scala\ntrait Greeter {\n  def greet(name: String): Unit =\n    println(\"Hello, \" + name + \"!\")\n}\n```\n\n- Extend traits using `extends` keyword\n- Override an implementationusing `override` keyword.\n\n```scala\nclass DefaultGreeter extends Greeter\n\nclass CustomizableGreeter(prefix: String, postfix: String) extends Greeter {\n  override def greet(name: String): Unit = {\n    println(prefix + name + postfix)\n  }\n}\n\nval greeter = new DefaultGreeter()\ngreeter.greet(\"Scala developer\") // Hello, Scala developer!\n\nval customGreeter = new CustomizableGreeter(\"How are you, \", \"?\")\ncustomGreeter.greet(\"Scala developer\") // How are you, Scala developer?\n```\n\n#### Main method\n\nSyntax for Scala's main method:\n```scala\nobject Main {\n  def main(args: Array[String]): Unit =\n    println(\"Hello, Scala developer!\")\n}\n```\n\n\n## [Unified Types](https://docs.scala-lang.org/tour/unified-types.html)\n\n![Type Hierarchy](./images/typeHierarchy.svg)\n\n\n## [Classes](https://docs.scala-lang.org/tour/classes.html)\n\n#### Private Members and Getter/Setter Syntax\n\nSetters use special syntax: `_=`\n\n```scala\nclass Point {\n  private var _x = 0\n  private val bound = 100\n\n  // Getter\n  def x = _x\n\n  // Setter\n  def x_= (newValue: Int): Unit = {\n    if (newValue \u003c bound) _x = newValue else printWarning\n  }\n\n  private def printWarning = println(\"WARNING: Out of bounds\")\n}\n\nval point1 = new Point\npoint1.x = 99\npoint1.y = 101 // prints the warning\n```\n\n[Alternative explanation on getters/setters](https://www.dustinmartin.net/getters-and-setters-in-scala/)\n\n\n## [Tuples](https://docs.scala-lang.org/tour/tuples.html)\n\n#### Accessing the elements\n\n```scala\nval ingredient = (\"Sugar\" , 25)\n\nprintln(ingredient._1) // Sugar\nprintln(ingredient._2) // 25\n```\n\n#### Pattern matching on tuples\n\nGrabbing values out of the tuple:\n\n```scala\nval (name, quantity) = ingredient\nprintln(name) // Sugar\nprintln(quantity) // 25\n```\n\nPattern matching using `foreach` and `case`:\n\n```scala\nval planets = List((\"Mercury\", 57.9), (\"Venus\", 108.2), (\"Earth\", 149.6))\n\nplanets.foreach {\n  case (\"Earth\", distance) =\u003e\n    println(s\"Our planet is $distance million kilometers from the sun\")\n  case _ =\u003e\n}\n```\n\nPattern matching in `for` loops:\n\n```Scala\nval numPairs = List((2, 5), (3, -7))\nfor ((a, b) \u003c- numPairs) {\n  println(a * b)\n}\n```\n\n#### Tuples and case classes\n\nVariables in tuples don't have names. If you want them to have names, use a \"case class\" instead.\n\nExample: `case class Planet(name: String, distance: Double)`\n\n\n## [Class composition with Mixins](https://docs.scala-lang.org/tour/mixin-class-composition.html)\n\nThis is how you can extend a subclass, and also have a \"trait\":\n\n```scala\nabstract class A {\n  val message: String\n}\nclass B extends A {\n  val message = \"I'm an instance of class B\"\n}\ntrait C extends A {\n  def loudMessage = message.toUpperCase()\n}\nclass D extends B with C\n\nval d = new D\nprintln(d.message)  // I'm an instance of class B\nprintln(d.loudMessage)  // I'M AN INSTANCE OF CLASS B\n```\n\n\n## [Higher Order Functions](https://docs.scala-lang.org/tour/higher-order-functions.html)\n\nHigher order functions are functions that take another function as a parameter.\n\n```scala\nval salaries = Seq(2, 7, 4)\nval newSalaries = salaries.map(x =\u003e x * 2) // List(4, 14, 8)\n```\n\nYou an alternatively write the 2nd line as:\n\n```scala\nval newSalaries = salaries.map(_ * 2)\n```\n\n\n## [Nested Methods](https://docs.scala-lang.org/tour/nested-functions.html)\n\nYou can nest methods in Scala.\n\n\n## [Multiple Parameter Lists (Currying)](https://docs.scala-lang.org/tour/multiple-parameter-lists.html)\n\nMain use cases:\n1. Passing a value to the 1st parameter list helps the 2nd parameter list infer the type\n1. Partial application\n\nHere is an example of \"partial application\" that lets us define `B` as `List[Int]`:\n\n```scala\ndef foldLeft[B](z: B)(op: (B, A) =\u003e B): B\n```\n\n```scala\nval numbers = List(1, 2, 3, 4, 5)\nval numberFunc = numbers.foldLeft(List[Int]()) _\n\nval squares = numberFunc((xs, x) =\u003e xs :+ x*x)\nprint(squares) // List(1, 4, 9, 16, 25)\n\nval cubes = numberFunc((xs, x) =\u003e xs :+ x*x*x)\nprint(cubes)  // List(1, 8, 27, 64, 125)\n```\n\n\n## [Pattern matching](https://docs.scala-lang.org/tour/pattern-matching.html)\n\n\"Switch statements\" from Java are called \"match expressions\" in Scala.\n\n#### Matching on case classes\n\n```scala\nabstract class Notification\n\ncase class Email(sender: String, title: String, body: String) extends Notification\n\ncase class SMS(caller: String, message: String) extends Notification\n```\n\n```scala\ndef showNotification(notification: Notification): String = {\n  notification match {\n    case Email(sender, title, _) =\u003e\n      s\"You got an email from $sender with title: $title\"\n    case SMS(number, message) =\u003e\n      s\"You got an SMS from $number! Message: $message\"\n  }\n}\n\nval someSms = SMS(\"12345\", \"Are you there?\")\nprintln(showNotification(someSms))  // prints You got an SMS from 12345! Message: Are you there?\n```\n\n#### Pattern guards\n\nPattern guards are boolean expressions that make cases more specific:\n\n```scala\ndef showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {\n  notification match {\n    case Email(sender, _, _) if importantPeopleInfo.contains(sender) =\u003e\n      \"You got an email from special someone!\"\n    case SMS(number, _) if importantPeopleInfo.contains(number) =\u003e\n      \"You got an SMS from special someone!\"\n    case other =\u003e\n      showNotification(other) // nothing special, delegate to our original showNotification function\n  }\n}\n```\n\n#### Other functionality\n\n- __matching on type__ - You can also match on \"type\" of the object\n- `sealed` - Traits and classes can be marked `sealed` which means all subtypes must be declared in the same file. This assures all subtypes are known. This is useful for pattern matching because we don't need a \"catch all\" case.\n\n\n## [Singleton Objects](https://docs.scala-lang.org/tour/singleton-objects.html)\n\n#### Companion objects\n\nScala uses __companion objects__ instead of Java's `static` keyword.\n\nAn object with the same name as a class is called a __companion object__. Conversely, the class is the object’s companion class. A companion class or object can access the private members of its companion.\n\nUse a companion object for methods and values which are not specific to instances of the companion class.\n\n```scala\nimport scala.math._\n\ncase class Circle(radius: Double) {\n  import Circle._\n  def area: Double = calculateArea(radius)\n}\n\nobject Circle {\n  private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)\n}\n\nval circle1 = Circle(5.0)\n\ncircle1.area\n```\n\n\n## [Regular Expression Patterns](https://docs.scala-lang.org/tour/regular-expression-patterns.html)\n\nAny string can be converted to a regular expression using the `.r` method.\n\n```scala\nimport scala.util.matching.Regex\n\nval numberPattern: Regex = \"[0-9]\".r\n\nnumberPattern.findFirstMatchIn(\"awesomepassword\") match {\n  case Some(_) =\u003e println(\"Password OK\")\n  case None =\u003e println(\"Password must contain a number\")\n}\n```\n\n\n## [For Comprehensions](https://docs.scala-lang.org/tour/for-comprehensions.html)\n\n`for each` loop example:\n\n```scala\ncase class User(name: String, age: Int)\n\nval userBase = List(User(\"Travis\", 28),\n  User(\"Kelly\", 33),\n  User(\"Jennifer\", 44),\n  User(\"Dennis\", 23))\n\nval twentySomethings = for (user \u003c- userBase if (user.age \u003e= 20 \u0026\u0026 user.age \u003c 30))\n  yield user.name // i.e. add this to a list\n\ntwentySomethings.foreach(name =\u003e println(name))  // prints Travis Dennis\n```\n\n`for each` loop example with 2 iterators:\n\n```scala\ndef foo(n: Int, v: Int) =\n   for (i \u003c- 0 until n;\n        j \u003c- 0 until n if i + j == v)\n   println(s\"($i, $j)\")\n\nfoo(10, 10) // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)\n```\n\n\n## [Generic Classes](https://docs.scala-lang.org/tour/generic-classes.html)\n\nA generic `Stack`:\n\n```scala\nclass Stack[A] {\n  private var elements: List[A] = Nil\n  def push(x: A) { elements = x :: elements }\n  def peek: A = elements.head\n  def pop(): A = {\n    val currentTop = peek\n    elements = elements.tail\n    currentTop\n  }\n}\n```\n\n```scala\nval stack = new Stack[Int]\nstack.push(1)\nstack.push(2)\nprintln(stack.pop)  // prints 2\nprintln(stack.pop)  // prints 1\n```\n\n\n## [Variances](https://docs.scala-lang.org/tour/variances.html)\n\n```scala\nclass Foo[+A] // Covariant class\nclass Bar[-A] // Contravariant class\nclass Baz[A]  // Invariant class\n```\n\n#### Covariance\n\nFor some class `List[+A]`, making `A` covariant implies that for two types `A` and `B` where `A` is a subtype of `B`, then `List[A]` is a subtype of `List[B]`\n\n- Given\n    - `A` is `Animal`\n    - `B` is `Cat`\n    - `Animal` is a subtype of `Cat`\n- Then\n    - `List[Animal]` is a subtype of `List[Cat]`\n\nScala's `List` class is `sealed abstract class List[+A]`, where the type parameter `A` is covariant\n\n#### Contravariance\n\nOpposite of Covariance.\n\nLet's say we literally had a printer that prints `Animal`s. Then it should be able to print `Cat`s as well. Covariance can help us model this scenario.\n\n- Given\n    - `A` is `Animal`\n    - `B` is `Cat`\n    - `Animal` is a subtype of `Cat`\n    - `abstract class Printer[-A]`\n    - `AnimalPrinter` extends `Printer[Animal]`\n    - `CatPrinter` extends `Printer[Cat]`\n    - `def printMyCat(printer: Printer[Cat])`\n- Then\n    - `Printer[Animal]` can be passed into `printMyCat`\n\n#### Invariance\n\nGeneric classes in Scala are invariant by default. This means that they are neither covariant nor contravariant.\n\nExample: If we make a custom `Container` class, then `Container[Cat]` is not a `Container[Animal]`. The reverse is not true either.\n\n\n## [Upper Type Bounds](https://docs.scala-lang.org/tour/upper-type-bounds.html)\n\nAn upper type bound `T \u003c: A` declares that type variable `T` refers to a subtype of type `A`\n\n- Given\n    - `Cat` extends `Pet`\n    - `Lion` extends `Animal`\n    - `class PetContainer[P \u003c: Pet](p: P) { def pet: P = p }`\n- Then\n    - `new PetContainer[Cat](new Cat)` compiles\n    - `new PetContainer[Lion](new Lion)` fails to compile\n\nCommon Pitfall: \"Variances\" and \"Upper Type Bounds\" are 2 different concepts. Notice you cannot replace `P \u003c: Pet` with `+P` since then `new PetContainer[Lion](new Lion)` would incorrectly succeed.\n\n\n## [Lower Type Bounds](https://docs.scala-lang.org/tour/lower-type-bounds.html)\n\nOpposite of Upper Type Bounds.\n\nCommon pitfall: \"functions are contravariant in their parameter types and covariant in their result types\". When making a type covariant by using `+B`, we will run into a problem when using `B` as a \"parameter type\" to a function. This is solved by using `U \u003e: B` instead. See [Lower Type Bounds](https://docs.scala-lang.org/tour/lower-type-bounds.html) for a full example.\n\n\n## [Inner Classes](https://docs.scala-lang.org/tour/inner-classes.html)\n\nScala allows classes to have other classes as members.\n\n\n## [Compound Types](https://docs.scala-lang.org/tour/compound-types.html)\n\nIf you have 2 traits: `Cloneable` and `Resetable`, then the syntax for a function to take an object with those 2 traits is:\n\n```scala\ndef cloneAndReset(obj: Cloneable with Resetable): Cloneable = {\n  //...\n}\n\n```\n\nIf it was 3 or more traits, the syntax would be `Trait1 with Trait2 with Trait3`\n\n\n## [Self-type](https://docs.scala-lang.org/tour/self-types.html)\n\nUnlikely I'll use this often. Self-types are used when 1 trait depends on another trait, but doesn't \"extend\" it. See [Self-type](https://docs.scala-lang.org/tour/self-types.html) for an example.\n\n\n## [Implicit Parameters](https://docs.scala-lang.org/tour/implicit-parameters.html)\n\nThis is when we mark a variable `implicit` in it's declaration, and `implicit` where it's used in a function, and the compiler will try to match the 2 together.\n\n- Given:\n    - value: `implicit val stringMonoid: Monoid[String]`\n    - value: `implicit val intMonoid: Monoid[Int]`\n    - method definition: `def sum[A](xs: List[A])(implicit m: Monoid[A]): A`\n- Then\n    - `m` will be matched with `intMonoid` if we call `sum(List(1, 2, 3))`\n\nSee [Implicit Parameters](https://docs.scala-lang.org/tour/implicit-parameters.html) for the full example.\n\n\n## [Polymorphic Methods](https://docs.scala-lang.org/tour/polymorphic-methods.html)\n\n#### Omitting the Type\n\nThe compiler knows `businessName` is a String:\n```scala\nval businessName = \"Montreux Jazz Café\"\n```\n\nThe compiler knows an `Int` will be returned:\n```scala\ndef squareOf(x: Int) = x * x\n```\n\nFor recursive functions, the compiler can't know the return type. The following code will fail:\n```scala\ndef fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)\n```\n\nCompiler can also infer the types:\n```scala\ncase class MyPair[A, B](x: A, y: B)\nval p = MyPair(1, \"scala\") // type: MyPair[Int, String]\n\ndef id[T](x: T) = x\nval q = id(1)              // type: Int\n```\n\n\n## [Operators](https://docs.scala-lang.org/tour/operators.html)\n\nIt's easy to \"overload\" an operator:\n\n```scala\ncase class Vec(x: Double, y: Double) {\n  def +(that: Vec) = Vec(this.x + that.x, this.y + that.y)\n}\n\nval vector1 = Vec(1.0, 1.0)\nval vector2 = Vec(2.0, 2.0)\n\nval vector3 = vector1 + vector2\nvector3.x  // 3.0\nvector3.y  // 3.0\n```\n\n\n## [By-name Parameters](https://docs.scala-lang.org/tour/by-name-parameters.html)\n\n_By-name_ parameters are only evaluated when used. They are in contrast to _by-value_ parameters. To make a parameter called by-name, prepend `=\u003e` to its type:\n\n```scala\ndef calculate(input: =\u003e Int) = input * 37\n```\n\nBy-name parameters have the advantage that they are not evaluated if they aren’t used in the function body. On the other hand, by-value parameters have the advantage that they are evaluated only once.\n\nThis ability to delay evaluation of a parameter until it is used can help performance if the parameter is computationally intensive to evaluate.\n\n\n## [Default Parameter Values](https://docs.scala-lang.org/tour/default-parameter-values.html)\n\n```scala\nclass Point(val x: Double = 0, val y: Double = 0)\n\nval point0 = new Point(1);    // point (1, 0)\nval point1 = new Point(y = 3) // point (0, 3)\n```\n\nFor `point1`, we use `y=3` (a named argument) since \"if the caller omits an argument, any following arguments must be named.\"\n\n\n## [Packages and Imports](https://docs.scala-lang.org/tour/packages-and-imports.html)\n\n#### Imports\n\n```scala\nimport users._  // import everything from the users package\nimport users.User  // import the class User\nimport users.{User, UserPreferences}  // Only imports selected members\nimport users.{UserPreferences =\u003e UPrefs}  // import and rename for convenience\n```\n\n## More notes\n\n#### Constructors\n\nClass constructor: private, public, read-only, mutable variables:\n\n```scala\nclass Ok[T](statusCode: Int, result: T) // private fields, but present on the constructor\n\nclass Ok[T](val statusCode: Int, val result: T) // public, read-only fields\n\nclass Ok[T](var statusCode: Int, var result: T) // public, mutable fields\n```\n\nOn a case class, \"when you use the case keyword, you do not need to use `val` to make a field public and read-only\":\n\n```scala\ncase class Ok[T](statusCode: Int, result: T)\n```\n\n#### [Null, null, Nil, Nothing, None, and Unit in Scala](https://sanaulla.info/2009/07/12/nothingness-2)\n\n- `Null` – it's a Trait.\n- `null` – it's an instance of `Null` - similar to Java null.\n- `Nil` – represents an empty List of anything of zero length.\n- `Nothing` - it's a Trait. Its a subtype of everything, but not superclass of anything. There are no instances of `Nothing`.\n- `None` – used with `Option` which has exactly 2 subclasses: `Some` and `None`. `None` is used to represent a sensible return value to avoid null pointer exceptions.\n- `Unit` – type used in method that doesn’t return a value.\n\n#### The `return` keyword\n\nIn Scala, it is encouraged to never use the `return` keyword. [A `return` expression, when evaluated, abandons the current computation and returns to the caller of the _method_ in which return appears](https://tpolecat.github.io/2014/05/09/return.html):\n\nCorrect:\n\n```scala\ndef sum(ns: Int*): Int = ns.foldLeft(0)((n, m) =\u003e n + m)\nsum(33, 42, 99)\n\n// Output\nres2: Int = 174\n```\n\nIncorrect: was expecting 174, but got 33.\n\n```scala\ndef sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) =\u003e return n + m)\nsumR(33, 42, 99)\n\n// Output\nres3: Int = 33\n```\n\n#### [`lazy val`](https://riptutorial.com/scala/example/10876/lazy-val)\n\n`lazy val` is a language feature where the initialization of a `val` is delayed until it is accessed for the first time. After that point, it acts just like a regular `val`.\n\nThere are 2 reasons to use `lazy val` in Scala\":\n\n1) Initialization is computationally expensive and `val` is not always used\n\n```scala\nlazy val tiresomeValue = {(1 to 1000000).filter(x =\u003e x % 113 == 0).sum}\nif (scala.util.Random.nextInt \u003e 1000) {\n  println(tiresomeValue)\n}\n```\n\n2) Resolving cyclic dependencies\n\nLet's look at an example with two objects that need to be declared at the same time during instantiation:\n\n```scala\nobject comicBook {\n  def main(args:Array[String]): Unit = {\n    gotham.hero.talk()\n    gotham.villain.talk()\n  }\n}\n\nclass Superhero(val name: String) {\n  lazy val toLockUp = gotham.villain\n  def talk(): Unit = {\n    println(s\"I won't let you win ${toLockUp.name}!\")\n  }\n}\n\nclass Supervillain(val name: String) {\n  lazy val toKill = gotham.hero\n  def talk(): Unit = {\n    println(s\"Let me loosen up Gotham a little bit ${toKill.name}!\")\n  }\n}\n\nobject gotham {\n  val hero: Superhero = new Superhero(\"Batman\")\n  val villain: Supervillain = new Supervillain(\"Joker\")\n}\n```\n\nBy using `lazy`, the reference can be assigned before it is initialized, without fear of having an uninitialized value.\n\n[Why not declare all vals lazy?](https://www.reddit.com/r/scala/comments/3x9x1x/when_to_use_lazy/) - Lazy initialization is thread safe, so declaring all `val`s as lazy would incur the overhead of ensuring thread safety, which is often not needed and would result in some unnecessary overhead for the usual case.\n\n## References\n\n- Notes are summarized from [Tour of Scala](https://docs.scala-lang.org/tour/tour-of-scala.html). All sections in their tutorial (other than \"Implicit Conversions\") were well written.\n- Article: [Nothingness](https://sanaulla.info/2009/07/12/nothingness-2) - summarized above.\n- Article: [The Point of No Return](https://tpolecat.github.io/2014/05/09/return.html) - went through first 2 examples, which are summarized above.\n- Article: [Scala Language - lazy val](https://riptutorial.com/scala/example/10876/lazy-val) - summarized above\n- Reddit post: [When to use 'lazy'](https://www.reddit.com/r/scala/comments/3x9x1x/when_to_use_lazy) - summarized most popular answer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frodneyshag%2Fscala","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frodneyshag%2Fscala","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frodneyshag%2Fscala/lists"}