Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not work in inline functions #88

Open
tschuchortdev opened this issue Apr 12, 2024 · 1 comment
Open

Does not work in inline functions #88

tschuchortdev opened this issue Apr 12, 2024 · 1 comment

Comments

@tschuchortdev
Copy link

It seems to me that record4s does not work correctly neither in inline nor transparent inline functions (the difference is important since they are inlined at different times iirc). Probably this is an issue with how the type checking of transparent functions works, so not strictly a bug in this library, but perhaps you can find a better workaround or escalate the issue to the Scala compiler. In any case, I hope that my report will at least serve as documentation for other users.

import com.github.tarao.record4s.%

%(name = "hello") + (bla = 123)

def foo() = {
  %(name = "hello") + (bla = 123)
}

inline def bar() = {
  %(name = "hello") + (bla = 123)
}

transparent inline def bob() = {
  %(name = "hello") + (bla = 123)
}

inline def foobar() = {
  (
    %(name = "hello").asInstanceOf[% { val name: String }]
      + (bla = 123)
  ).asInstanceOf[% { val name: String; val bla: Int }]
}

foobar()

Output:

val res0: com.github.tarao.record4s.%{val name: String; val bla: Int} = %(name = hello, bla = 123)

def foo(): com.github.tarao.record4s.%{val name: String; val bla: Int}

-- [E008] Not Found Error: -----------------------------------------------------
2 |  %(name = "hello") + (bla = 123)
  |  ^^^^^^^^^^^^^^^^^^^
  |value + is not a member of Any, but could be made available as an extension method.
  |
  |One of the following imports might make progress towards fixing the problem:
  |
  |  import math.Fractional.Implicits.infixFractionalOps
  |  import math.Integral.Implicits.infixIntegralOps
  |  import math.Numeric.Implicits.infixNumericOps
  |
1 error found

-- [E008] Not Found Error: -----------------------------------------------------
2 |  %(name = "hello") + (bla = 123)
  |  ^^^^^^^^^^^^^^^^^^^
  |value + is not a member of Any, but could be made available as an extension method.
  |
  |One of the following imports might make progress towards fixing the problem:
  |
  |  import math.Fractional.Implicits.infixFractionalOps
  |  import math.Integral.Implicits.infixIntegralOps
  |  import math.Numeric.Implicits.infixNumericOps
  |
1 error found

def foobar(): com.github.tarao.record4s.%{val name: String; val bla: Int}

val res1: com.github.tarao.record4s.%{val name: String; val bla: Int} = %(name = hello, bla = 123)

PS: Let me just say that this is an amazing library that doesn't have nearly as many stars as it deserves. It is not only surprisingly usable, but also serves as a good example of whitebox macro techniques 👍

@tarao
Copy link
Owner

tarao commented Apr 14, 2024

Aha, I didn't know this behavior but it seems that this is the semantics of inlining.

See this:
scala/scala3#12754

I agree that I should mention this in the documentation.

Possible workarounds (work only for transparent inline methods)

1. Define the record outside the method

      val r = %(name = "hello")

      transparent inline def bob() = {
        r + (bla = 123)
      }

      val r1 = bob()
      r1.name
      r1.bla

2. Define the record as an argument

      transparent inline def bob[R <: %](r: R = %(name = "hello")) = {
        r + (bla = 123)
      }

      val r1 = bob()
      r1.name
      r1.bla

Note: this is a restricted version of generic record concatenation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants