Skip to content

Instantly share code, notes, and snippets.

@rahulkumar-aws
Created November 10, 2018 13:51
Show Gist options
  • Save rahulkumar-aws/266c0cbfc0bb72951aab99143f9c15a5 to your computer and use it in GitHub Desktop.
Save rahulkumar-aws/266c0cbfc0bb72951aab99143f9c15a5 to your computer and use it in GitHub Desktop.
object Functions extends App {

  //
  // Function Calls
  //

  // basic function call with a single param
  println("foo")


  // function call with a block param
  println { "foo" }


  // function call with a more complex block param
  println {
    val f = "f"
    f + "oo"
  }


  // fully qualified function call
  Predef.println("foo")


  // infix function call
  Predef println "foo"


  // named param function call
  println(x = "foo")


  // optional parens for no-param function
  // Note: println is overloaded taking either no params or a single param
  println()
  println


  // identifier
  `println`("foo")


  //
  // Function Definitions
  //

  // no params for a function def
  def noParams = scala.util.Random.alphanumeric.take(8).mkString

  println(noParams)


  // parens for a no-param function def
  def noParamsWithParens() = scala.util.Random.alphanumeric.take(8).mkString

  println(noParamsWithParens)


  // def with a return type
  def noParamsWithParensAndReturnType(): String = scala.util.Random.alphanumeric.take(8).mkString

  println(noParamsWithParensAndReturnType)


  // single param def
  def aSingleParamDef(s: String) = s.toUpperCase

  println(aSingleParamDef("foo"))


  // function body in a block
  def aSingleParamDefBlock(s: String) = {
    s.toUpperCase
  }

  println(aSingleParamDefBlock("foo"))


  // function body in parens
  def aSingleParamDefParens(s: String) = (
    s.toUpperCase
  )

  println(aSingleParamDefParens("foo"))


  // single param and return type
  def aSingleParamDefWithReturnType(s: String): String = s.toUpperCase

  println(aSingleParamDefWithReturnType("foo"))


  // function val
  val aSingleParamFunctionVal = (s: String) => s.toUpperCase

  println(aSingleParamFunctionVal("foo"))


  // function val with body in a block
  val aSingleParamFunctionValBlock = {
    (s: String) => s.toUpperCase
  }

  println(aSingleParamFunctionValBlock("foo"))


  // two param def
  def twoParamDef(s: String, i: Int): String = s.take(i)

  println(twoParamDef("hello", 2))


  // multiple parameter sets
  def twoParamSetsDef(s: String)(i: Int): String = s.take(i)

  println(twoParamSetsDef("hello")(2))


  // partially applied function
  val partiallyAppliedFunction = twoParamSetsDef("hello")(_)

  println(partiallyAppliedFunction(3))


  // partially applied function where the second parameter is applied
  val anotherPartiallyAppliedFunction: (String => String) = twoParamSetsDef(_)(1)

  println(anotherPartiallyAppliedFunction("foo"))


  // polymorphic type parameter for a def
  def typeParamDef[T](o: Option[T]): Boolean = o.isDefined

  println(typeParamDef(Some("foo")))
  println(typeParamDef[String](Some("foo")))


  // create an instance of a single parameter function
  val aFunction1 = new Function1[String, String] {
    override def apply(s: String): String = s.toUpperCase
  }

  println(aFunction1("foo"))


  // create an instance of a single parameter function but use parens after the type
  val aFunction1WithParens = new Function1[String, String]() {
    override def apply(s: String): String = s.toUpperCase
  }

  println(aFunction1WithParens("foo"))


  // shorthand for creating a new single parameter function
  val anotherFunction1 = new (String => String) {
    override def apply(s: String): String = s.toUpperCase
  }

  println(anotherFunction1("foo"))


  // single input parameters can optionally be wrapped in parens
  val yetAnotherFunction1 = new ((String) => String) {
    override def apply(s: String): String = s.toUpperCase
  }

  println(yetAnotherFunction1("foo"))


  // shorthand for a single parameter function
  val andAnotherFunction1 = (s: String) => s.toUpperCase

  println(andAnotherFunction1("foo"))


  // shorthand for a partial function val
  val aPartialFunction: PartialFunction[String, String] = {
    case s: String => s.toUpperCase
  }

  println(aPartialFunction("foo"))


  // shorthand for a partial function def
  def aPartialFunctionDef: PartialFunction[String, String] = {
    case s: String => s.toUpperCase
  }

  println(aPartialFunctionDef("foo"))


  // create a new instance of a partial function
  val anotherPartialFunction = new PartialFunction[String, String] {
    override def isDefinedAt(s: String): Boolean = true
    override def apply(s: String): String = s.toUpperCase
  }

  println(anotherPartialFunction("foo"))


  // an operator
  def &%->(): String = "foo"

  println(&%->())


  // right-associative by putting a colon on the right side of the method name
  class Foo {
    def #:(s: String): String = s.reverse
  }

  val foo = new Foo

  // normal operator call
  println(foo.#:("asdf"))

  // reverse infix call
  println("asdf" #: foo)


  // no equals necessary for functions that return Unit
  def returnsUnit() {
    println("bad form")
  }

  returnsUnit()


  // call by name params are evaluated each time the are accessed
  def callByName(byName: => String, byValue: String): Unit = {
    println(byName, byValue)
    println(byName, byValue)
  }

  callByName(scala.util.Random.alphanumeric.take(8).mkString, scala.util.Random.alphanumeric.take(8).mkString)


  // default values
  def defaultValues(s: String = "asdf") = s.toUpperCase

  //
  println(defaultValues("foo"))

  // the parens are required
  println(defaultValues())


  //
  // Higher-order Functions
  //

  // a function that takes a string and returns it in upper case
  def toUpperCase(s: String): String = s.toUpperCase

  // a higher-order function that takes a function, and calls it with the string "foo"
  def aHigherOrderFunction(f: String => String): String = f("foo")

  println(aHigherOrderFunction(toUpperCase))


  // single input type parameters can optionally be wrapped with parens
  def anotherHigherOrderFunction(f: (String) => String): String = f("foo")

  println(anotherHigherOrderFunction(toUpperCase))


  // multiple input type parameters must be wrapped with parens
  def multipleInputParamHigherOrderFunction(f: (String, Int) => String): String = f("foo", 1)


  // no input type parameters
  // note: the call to f must use parens in this context
  def noInputParamHigherOrderFunction(f: () => String): String = f()


  // a higher-order function that returns a function
  def returnsAHigherOrderFunction: (String => String) = toUpperCase

  println(returnsAHigherOrderFunction("foo"))


  // anonymous function where s is the string input parameter
  println {
    anotherHigherOrderFunction { s =>
      s.toUpperCase
    }
  }


  // anonymous function with input type specified
  println {
    anotherHigherOrderFunction { s: String =>
      s.toUpperCase
    }
  }


  // anonymous function with partial function from a case statement
  println {
    anotherHigherOrderFunction { case s: String =>
      s.toUpperCase
    }
  }


  // anonymous function with multiple params
  println {
    multipleInputParamHigherOrderFunction { (s, i) =>
      s.take(i)
    }
  }


  // anonymous function with multiple params via a case statement
  println {
    multipleInputParamHigherOrderFunction { case (s: String, i: Int) =>
      s.take(i)
    }
  }


  // shorthand anonymous function
  println(anotherHigherOrderFunction(_.toUpperCase))


  // polymorphic type param with a higher-order function
  def aTypeParamedHigherOrderFunction[T](f: String => T) = f("foo")

  println(aTypeParamedHigherOrderFunction(_.length))
  println(aTypeParamedHigherOrderFunction[Int](_.length))

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment