My function has 1 parameter and type is string but lenght is 4, Can I validate this parameter in compile time?
In haskell and F# have type level and it can validation in compile time, like nonEmptyList.
How to make it in scala. I think shapless can do this but I don't understand
Thank you for advance suggestion
Yes, Shapeless can do this. Perhaps something like this:
def f(s: Sized[IndexedSeq[Char], Nat._4]): ...
You wouldn't be able to pass strings directly to this, though. You'd have to do something like f(Sized('a', 'b', 'c', 'd'))
You can't with vanilla Scala.
The best approach you can go is creating a special type for this -
case class SpecialString(string: String) {
require(string.length == 4)
}
Then, make your function receive SpecialString as a parameter instead of a String.
Using macros is also an option for compile-time validation. See this post by Arnout Engelen: http://blog.xebia.com/compile-time-evaluation-scala-macros/
I've modified his example to define a string-validating function:
object CompileTimeStringCheck {
import scala.language.experimental.macros
// This function exposed to consumers has a normal Scala type:
def stringCheck(s: String): String =
// but it is implemented as a macro:
macro CompileTimeStringCheck.stringCheck_impl
import scala.reflect.macros.blackbox.Context
// The macro implementation will receive a 'Context' and
// the AST's of the parameters passed to it:
def stringCheck_impl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
import c.universe._
// We can pattern-match on the AST:
s match {
case Expr(Literal(Constant(nValue: String))) =>
// We perform the calculation:
val result = normalStringCheck(nValue)
// And produce an AST for the result of the computation:
c.Expr(Literal(Constant(result)))
case other =>
// Yes, this will be printed at compile time:
println("Yow!")
???
}
}
// The actual implementation is regular old-fashioned scala code:
private def normalStringCheck(s: String): String =
if (s.length == 4) return s
else throw new Exception("Baaaaaah!")
}
Here's the catch, though: This needs to be compiled before it can be used, i.e. put it into a utils jar or something. Then you can use it at a later compile time:
import CompileTimeStringCheck._
object Test extends App {
println(stringCheck("yes!"))
}
Again, see Arnout Engelen's post for more details and the original solution (http://blog.xebia.com/compile-time-evaluation-scala-macros/).
Related
I have object
object func1{
def something(arg1: Int): String{
// var date = something2()
// Using date
}
def something2(): LocalDate{
LocalDate.now()
}
}
I want to write a test on something method, How can I mock something2
You can't make static methods. So, you need to do something like this:
def something(val now: () => Date = LocalDate.now) = ...
Then, in your production code, you do val foo = something() as you normally would, but in your test, you can do things like
something(_ => new Date(0l)) shouldBe foo
or
val date = mock[Function0[Date]]
when(date.apply()).thenReturn(new Date(0l))
something(date) shouldBe foo
If the code's functionality depends on the time, it's definitely recommended that you have a second look at the code you're testing and explicitly pass a Clock as a parameter or something along those lines (e.g. a function as suggested in other comments) to make its behavior easy to test.
If you are testing this to make sure that a field somewhere indeed contains the time returned by LocalDate.now() please consider that you might be testing the behavior of LocalDate rather than your own code's, so probably mocking that doesn't really give you anything.
If timing is fundamental to the function's behavior and you have no control over it, I believe you might somehow use Mockito's ability to mock static objects. I came up with the following which compiles, but I'm not sure about whether it works or not (since I believe it relies on some bytecode manipulation black magic which might make your testing suite brittle, so beware):
import scala.util.{Try, Using}
import java.time.{Clock, Instant, LocalDate, ZoneId}
import org.mockito.Mockito._
def withClock[A](clock: Clock)(f: => Unit): Try[Unit] = {
Using(mockStatic(classOf[LocalDate])) { mocked =>
mocked.when(() => LocalDate.now()).thenReturn(LocalDate.now(clock))
f
}
}
withClock(Clock.fixed(Instant.ofEpochMilli(42), ZoneId.of("UTC"))) {
assert(LocalDate.now().toEpochDay() == 0)
}
We have been banging our heads for a while on this but we cannot find a solution.
In our project we would like to write some DSL to migrate some old code in our codebase.
We would like to make a macro that given an instance of a case class gives us the possibility to extract the value in a typesafe manner. In this case it should be possible to declare x of type Int.
case class MyPersonalCaseClass(token: Int, str: String)
val someVariable = MyPersonalCaseClass(123, "SOMESTRING")
val x = Macros.->(someVariable, "token")
Here “token” is a compile-time constant, referring to the field name.
The macro can be declared with something like
def ->[T](value:T,key: String): Any = macro MacrosImpl.arrow[T]
As for our understanding the only way was with whitebox macros, feel free to change the signatures.
def arrow[T: c.WeakTypeTag](c: whitebox.Context)(value: c.Expr[T], key:c.Expr[String]): c.Expr[Any] =
{
import c.universe._
val caseClassType: c.universe.Type = weakTypeOf[T]
???
}
Scala version is “2.12.8”.
The reason we need something like this is we are porting a lot of code from perl and we would like to give the programmers a vagueish idea they are still writing it.
thanks in advance!
Try
import shapeless.LabelledGeneric
import shapeless.record._
LabelledGeneric[MyPersonalCaseClass].to(someVariable).get(Symbol("token")) // 123
I'm thinking if its possible to create some sort of data structure that would take a string as a parameter and if that string does not contains .txt or something like that it would give me a compile error?
I can be specific on my problem - I am trying to take a file as a parameter(Source) to a function but I am told that currently I am passing any kind of file and it only should take text files so it is not done correctly. How do i approach this?
-Thanks!! ^^
Yes, this is not a problem. The big question is should you do it though. If your code is a library of sorts then under certain circumstances this might make sense. Check out Uri.uri from the http4s project
In your case the implementation could look something like this:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
class Macros(val c: Context) {
import c.universe._
def txtFile(fileName: c.Expr[String]): Tree =
fileName.tree match {
case Literal(Constant(s: String)) if s.endsWith(".txt") =>
fileName.tree
case _ =>
c.abort(
c.enclosingPosition,
s"Supplied parameter is not a text file"
)
}
}
object MyObject {
def txtFile(fileName: String): String = macro Macros.txtFile
}
You'd use this like:
val x: String = txtFile("abc.tx") // Fails to compile
val y: String = txtFile("abc.txt") // Compiles
Again, it can be done, but you probably want to go with Option :-)
Assuming that String is coming from somewhere other than the code base (web request, cmd line), you'll need to pass that String to something that accepts Strings. Thus you'll have a point at which you're converting a String to your special filename datatype. So I can't see any way you'll be able to protect against some kind of runtime check.
If you want a runtime check that will avoid an error, you could return an Option, returning None if the String isn't a valid filename
You could use the refined library:
type TxtSuffix = EndsWith[W.`".txt"`.T]
type TxtFile = String Refined TxtSuffix
In order to construct a TxtFile, you need to give it a string that ends with ".txt":
val file: TxtFile = refineMV[TxtSuffix]("some.pdf") // compiler error
error: Predicate failed: "some.pdf".endsWith(".txt")
I'm trying to implement something like clever parameters converter function with Scala.
Basically in my program I need to read parameters from a properties file, so obviously they are all strings and I would like then to convert each parameter in a specific type that I pass as parameter.
This is the implementation that I start coding:
def getParam[T](key : String , value : String, paramClass : T): Any = {
value match {
paramClass match {
case i if i == Int => value.trim.toInt
case b if b == Boolean => value.trim.toBoolean
case _ => value.trim
}
}
/* Exception handling is missing at the moment */
}
Usage:
val convertedInt = getParam("some.int.property.key", "10", Int)
val convertedBoolean = getParam("some.boolean.property.key", "true", Boolean)
val plainString = getParam("some.string.property.key", "value",String)
Points to note:
For my program now I need just 3 main type of type: String ,Int and Boolean,
if is possible I would like to extends to more object type
This is not clever, cause I need to explicit the matching against every possibile type to convert, I would like an more reflectional like approach
This code doesn't work, it give me compile error: "object java.lang.String is not a value" when I try to convert( actually no conversion happen because property values came as String).
Can anyone help me? I'm quite newbie in Scala and maybe I missing something
The Scala approach for a problem that you are trying to solve is context bounds. Given a type T you can require an object like ParamMeta[T], which will do all conversions for you. So you can rewrite your code to something like this:
trait ParamMeta[T] {
def apply(v: String): T
}
def getParam[T](key: String, value: String)(implicit meta: ParamMeta[T]): T =
meta(value.trim)
implicit case object IntMeta extends ParamMeta[Int] {
def apply(v: String): Int = v.toInt
}
// and so on
getParam[Int](/* ... */, "127") // = 127
There is even no need to throw exceptions! If you supply an unsupported type as getParam type argument, code will even not compile. You can rewrite signature of getParam using a syntax sugar for context bounds, T: Bound, which will require implicit value Bound[T], and you will need to use implicitly[Bound[T]] to access that values (because there will be no parameter name for it).
Also this code does not use reflection at all, because compiler searches for an implicit value ParamMeta[Int], founds it in object IntMeta and rewrites function call like getParam[Int](..., "127")(IntMeta), so it will get all required values at compile time.
If you feel that writing those case objects is too boilerplate, and you are sure that you will not need another method in these objects in future (for example, to convert T back to String), you can simplify declarations like this:
case class ParamMeta[T](f: String => T) {
def apply(s: String): T = f(s)
}
implicit val stringMeta = ParamMeta(identity)
implicit val intMeta = ParamMeta(_.toInt)
To avoid importing them every time you use getParam you can declare these implicits in a companion object of ParamMeta trait/case class, and Scala will pick them automatically.
As for original match approach, you can pass a implicit ClassTag[T] to your function, so you will be able to match classes. You do not need to create any values for ClassTag, as the compiler will pass it automatically. Here is a simple example how to do class matching:
import scala.reflect.ClassTag
import scala.reflect._
def test[T: ClassTag] = classTag[T].runtimeClass match {
case x if x == classOf[Int] => "I'm an int!"
case x if x == classOf[String] => "I'm a string!"
}
println(test[Int])
println(test[String])
However, this approach is less flexible than ParamMeta one, and ParamMeta should be preferred.
Is it possible to get the name of a scala variable at runtime?
E.g. is it possible to write a function getIntVarName(variable: Int): String behaving as follows?
val myInt = 3
assert("myInt" === getIntVarName(myInt))
For what you need to do, It seems to me that runtime is not required, since you already have your myInt variable defined at compile time. If this is the case, you just need a bit of AST manipulation via a macro.
Try
package com.natalinobusa.macros
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object Macros {
// write macros here
def getName(x: Any): String = macro impl
def impl(c: Context)(x: c.Tree): c.Tree = {
import c.universe._
val p = x match {
case Select(_, TermName(s)) => s
case _ => ""
}
q"$p"
}
}
Be aware that macro's must be compiled as a separate subproject, and cannot be part of the same project where the macro substitution has to be applied. Check this template on how to define such a macro sub-project: https://github.com/echojc/scala-macro-template
scala> import Macros._
import Macros._
scala> val myInt = 3
myInt: Int = 3
scala> "myInt" == getName(myInt)
res6: Boolean = true
You can use scala-nameof to get a variable name, function name, class member name, or type name. It happens at compile-time so there's no reflection involved and no runtime dependency needed.
val myInt = 3
assert("myInt" === nameOf(myInt))
will compile to:
val myInt = 3
assert("myInt" === "myInt")
Basically, it can't be done.
The JVM offers nothing by way of a Method handle (remember, Scala properties are encoded as methods in bytecode to support the uniform access principle). The closest you can get is to use reflection to find a list of methods defined on a particular class - which I appreciate doesn't help with your particular need.
It is possible to implement this as a Scala feature, but it would require a compiler plugin to grab the relevant symbol name from the AST and push it into code as a string literal, so not something I could demonstrate in a short code snippet :)
The other naming problem that often comes up in reflection is method parameters. That one at least I can help with. I have a work-in-progress reflection library here that's based on the compiler-generated scala signature as used by scalap. It's nowhere near being ready for serious use, but it is under active development.
Scala doesn't yet have much more than Java in terms of metadata like this. Keep an eye on the Scala Reflection project, but I doubt that will offer access to local variables anytime soon. In the meantime, consider a bytecode inspector library like ASM. Another big caveat: local variable names are lost during compilation, so you'd need to compile in "debug" mode to preserve them.
I don't think it's possible to get the name of a variable, but you can try it with objects:
object Test1 {
def main(args: Array[String]) {
object MyVar {
def value = 1
}
println(MyVar.getClass)
}
}
This prints: class Test1$MyVar$2$. So you can get 'MyVar' out of it.
This can be achieved with Scala 3 Macros (does it at compile time).
Create a Macro object (this must be in a separate file):
import scala.quoted.{Expr, Quotes}
object NameFromVariable :
def inspectCode(x: Expr[Any])(using Quotes): Expr[String] =
val name = x.show.split("""\.""").last
Expr(name)
Then you need an inline method in your class.
inline def getIntVarName(inline x: Any): Any = ${ NameFromVariable.inspectCode('x) }
And use this method, like:
val myInt = 3
assert("myInt" === getIntVarName(myInt))
See the official documentation: https://docs.scala-lang.org/scala3/guides/macros/macros.html