question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Interplay between inline constants and inline parameters

See original GitHub issue

Perhaps I’m missing something about how inline constants and inline params are supposed to work together. Below are a couple examples where compiler’s behaviour is confusing. I expected inline vals to act like compile time constant (so that I could use them to build a DSL for some compile-time code generation), but it seems my intuition is not exactly correct.

Some clarification would be really helpful!

Compiler version

3.0.0-RC1

Simple example

object Str:
    inline def concat(inline a: String, inline b: String): String =
        ${ evalConcat('a, 'b) }
    
    def evalConcat(expra: Expr[String], exprb: Expr[String])(using Quotes): Expr[String] =
        val a = expra.valueOrError
        val b = exprb.valueOrError
        Expr(a ++ b)

// This works just fine
println(Str.concat("Hello, ", "Scala 3"))

inline val str1 = "Hello, "
inline val str2 = "Scala 3"
// While this doesn't compile with
// "Expected a known value". The value of: str1 could not be extracted using scala.quoted.FromExpr$PrimitiveFromExpr@4a8ebad7
println(Str.concat(str1, str2))

I’d expect that inline constant would get inlined at the use-site and both variants would work the same, but it seems that in the 2nd variant FromExpr sees str1 rather than its constant value "Hello, ".

More complex example

This is the setup. concat does compile-time concatenation of Bag contents.

case class Bag(things: Seq[Char])

object Bag:
    given ToExpr[Bag] with
        def apply(x: Bag)(using Quotes): Expr[Bag] =
            '{ Bag(${Expr(x.things)}) }

    given FromExpr[Bag] with
        def unapply(x: Expr[Bag])(using Quotes): Option[Bag] =
            x match
            case '{ Bag(${Expr(things)}) } => Some(Bag(things))
            case _ => None
    
    inline def concat(inline a: Bag, inline b: Bag): Bag =
        ${ evalConcat('a, 'b) }
    
    def evalConcat(expra: Expr[Bag], exprb: Expr[Bag])(using Quotes): Expr[Bag] =
        val a = expra.valueOrError
        val b = exprb.valueOrError
        val things = a.things ++ b.things
        Expr(Bag(things))

Then this works just fine

println(Bag.concat(Bag(Seq('a', 'b', 'c')), Bag(Seq('d', 'e')))) // => Bag(ArraySeq(a, b, c, d, e))

However, this doesn’t compile:

inline val bagA = Bag(Seq('a', 'b', 'c'))
// inline value must have a literal constant type

This is somewhat confusing – it’s OK for Bag(Seq('a', 'b', 'c')) to be an argument to an inline parameter, why is it not OK for the same expression to be an RHS for an inline constant?

Furthermore, here the compilation error is no longer about RHS of an inline value, but it now complains about not being able to FromExpr.unapply argument bagA of Bag.concat.

inline val bagA = Bag(Seq('a', 'b', 'c'))
inline val bagB = Bag(Seq('a', 'b', 'c'))
println(Bag.concat(bagA, bagB))
// Error: The value of: bagA could not be extracted using org.scalex.Bag$given_FromExpr_Bag$@59323a86

The fact that the compilation error is not not about inline val but is rather about bagA argument is misleading.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
artempyanykhcommented, Mar 23, 2021

Thanks @nicolasstucki, your help is much appreciated!

1reaction
nicolasstuckicommented, Mar 23, 2021

This doesn’t compile: error on line 3: The value of: str1 could not be extracted

inline val str1 = "Hello, "
inline val str2 = "Scala 3"
println(Str.concat(str1, str2))

that might be a bug

Read more comments on GitHub >

github_iconTop Results From Across the Web

Inline | Macros in Scala 3
The simplest form of inlining is to inline constants in programs: ... Inline parameters. Inline parameters do not create bindings and are simply...
Read more >
Constants and Inline Functions (Contd.) (Lecture 09) - YouTube
Programming in C++ - Dr. Partha Pratim Das. Constants and Inline Functions (Contd.) (Lecture 09). 56K views 6 years ago.
Read more >
Inline Numeric Values of Block Parameters - MathWorks
This example shows how to optimize the generated code by inlining the numeric values of block parameters. Block parameters include the Gain parameter...
Read more >
Why does an inline function need pass arguments?
If a function is inline, the compiler places a copy of the code of that function at each point where the function is...
Read more >
Inlining - Optimization and Programming Guide - IBM
Inlining. Inlining is the process of replacing a subroutine or function call at the call site with the body of the subroutine or...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found