Package

com.thoughtworks

feature

Permalink

package feature

Visibility
  1. Public
  2. All

Type Members

  1. final class Caller[+A] extends AnyVal

    Permalink

    An implicit value that points to the function caller.

    An implicit value that points to the function caller.

    Usage

    libraryDependencies += "com.thoughtworks.feature" %% "caller" % "latest.release"
    Getting the caller for logging or something
    object Foo{
      def log()(implicit caller: Caller[Any]) = {
        println(caller.value)
      }
    }
    object Bar{
      Foo.log() // Bar
    }
    Restricting who you can be called from
    class IKnowWhatImDoing
    object Foo{
      def runDangerous()(implicit caller: Caller[IKnowWhatImDoing]) = {
        println(caller.value)
      }
    }
    object Bar {
      Foo.runDangerous() // compile error
    }
    object Bar2 extends IKnowWhatImDoing{
      Foo.runDangerous() // ok, prints Bar2
    }
    Getting calling class or classloader, e.g. for loading resources, without needing to worry about properly setting up and tearing down the Context ClassLoader
    object Foo{
      def getResource(path: String)(implicit caller: Caller[_]) = {
        caller.value.getClass.getClassLoader.getResourceAsStream(path)
      }
    }
    object Bar{
      Foo.getResource("/thing/file.txt") // loads resource from `Bar`s classloader, always
    }
    Authors:

    Li Haoyi

    杨博 (Yang Bo) <[email protected]>

  2. final class Constructor[F] extends AnyVal

    Permalink

    An implicit value to dynamically creating classes and traits, especially dynamic mixins.

    An implicit value to dynamically creating classes and traits, especially dynamic mixins.

    Usage

    libraryDependencies += "com.thoughtworks.feature" %% "constructor" % "latest.release"
    trait A
    trait B
    
    def makeAWithB()(implicit constructor: Constructor[() => A with B]): A with B = {
      constructor.newInstance()
    }
    
    val ab: A with B = makeAWithB()

    Motivation

    This feature is useful for library authors. A library author may ask his user to create a trait type, then dynamically mix-in it with the features provided by the library.

    Suppose you are creating a DSL that compiles to JavaScript.

    You want your DSL is extensible. For example, the DSL users should be able to create custom binary operators.

    With the help of Constructor.scala, you can put the boilerplate code into a private class BinaryOperator:

    trait Ast
    
    object Ast {
    
      class Literal(val n: Int) extends Ast {
        override final def compile(): String = n.compile()
      }
    
      private[Ast] abstract class BinaryOperator(leftHandSide: Ast, rightHandSide: Ast) extends Ast {
        protected def symbol: String
        override final def compile() = s"($leftHandSide $symbol $rightHandSide)"
      }
    
      def binaryOperator[T](leftHandSide: Ast, rightHandSide: Ast)(
        implicit constructor: Constructor[(Ast, Ast) => BinaryOperator with T]): BinaryOperator with T = {
        constructor.newInstance(leftHandSide, rightHandSide)
      }
    
    }

    The users of only need a very simple implementation for their custom binary operators.

    import Ast._
    
    trait Plus {
      protected final def symbol = "+"
    }
    
    trait Minus {
      protected final def symbol = "-"
    }
    
    val myAst = binaryOperator[Plus](
      new Literal(1),
      binaryOperator[Minus](
        new Literal(3),
        new Literal(5)
      )
    )
    
    print(myAst.compile()) // Output: "(1 + (3 - 5))"

    An alternative approach

    There is another approach to integrate partial implementation from users: asking users to provide custom callback functions or type classes.

    However, the callback functions or type classes approach will create additional object instances and additional references for each instance at run-time. On the other hand, the Constructor.scala approach create classes at compile-time and no additional run-time references. As a result, at run-time, Constructor.scala approach will consume less memory, and performs less indirect access on memory.

    Author:

    杨博 (Yang Bo) <[email protected]>

  3. trait Demixin[ConjunctionType] extends AnyRef

    Permalink
  4. trait Mixin[SuperTypes <: HList] extends AnyRef

    Permalink
  5. final class Override[Vals, Result] extends AnyVal with Dynamic

    Permalink

    Author:

    杨博 (Yang Bo) <[email protected]>

  6. class Untyper[Universe <: Singleton with Universe] extends AnyRef

    Permalink

    Author:

    杨博 (Yang Bo) <[email protected]>

Value Members

  1. object Caller

    Permalink
  2. object Constructor

    Permalink
  3. object Demixin

    Permalink
  4. object Mixin extends LowPriorityMixin

    Permalink
  5. object Override

    Permalink

Ungrouped