Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is actually possible to deprecate Scala case class fields?

Given

case class Fruit(name: String, colour: String)

I'd like to deprecate the case class field colour.

I tried to achieve the former by both employing Scala @deprecated

case class Fruit(name: String, @deprecated("message", "since") colour: String)

and Java @Deprecated annotation

case class Fruit(
  name: String, 
  /* @Deprecated with some message here */
  @(Deprecated @field) 
  colour: String
)

Unfortunately I wasn't able to make colour deprecated in any case and I'm not able to find any resource on that.

Indeed, I can achieve the same task using other approaches, e.g. by relaxing my case class to a normal class and provide a getter for colour and make the latter deprecated, but I would like to know if deprecating case class fields is actually not possible and -- eventually -- the reason why.

Thank you.


UPDATE

As Mike rightly pointed out, colour is a required field for a case class, so the sense of setting this attribute to deprecated is arguable. I'd like to deprecate colour , since I'm now providing colour information from another construct, I want to keep the user knowing that colour is not the right instance by where fetch that information, and I will remove it from Fruit in next releases.

By now, I'd just like warn users to not fetch colour information from the Fruit attribute and, temporarily, I don't really care if they can create instances of fruit with colour information.


UPDATE 2

As Alexey said, I do have the deprecated warning at compile time. But why can't I observe the deprecation in my IDE code as well as I'd deprecating a method, then? I'd expect something like the following

val fruit = Fruit("peer", "green")
val colour = fruit.colour

I'm using IntelliJ.

like image 296
spi-x-i Avatar asked Mar 20 '18 13:03

spi-x-i


2 Answers

Your first version seems to work fine: if you paste

case class Fruit(name: String, @deprecated("message", "since") colour: String)

println(Fruit("", "").colour)

at https://scastie.scala-lang.org/, you'll see the deprecation warning. Of course, you need to access the field, whether directly or through an extractor:

Fruit("", "") match { case Fruit(x, y) => y }

will also warn.

That IDEA doesn't show colour as deprecated is I believe just a bug. In general it's quite unreliable in showing errors and warnings in Scala code inline and you should always check by actually building the project.

like image 106
Alexey Romanov Avatar answered Nov 15 '22 14:11

Alexey Romanov


This is an odd use case. If a required field is deprecated, then the class itself must be deprecated too, surely? That is, assuming what you're trying to do is possible, it's impossible to use the class at all without getting a deprecation warning. (This probably explains why it's not possible.)

That said, as you indicate, there are ways to achieve what you're trying to do. Here's one of them:

case class Fruit(name: String) {

  @deprecated("message", "since")
  val colour: String = "some default value"
}

object Fruit {

  // Deprecated factory method.
  @deprecated("message", "since")
  def apply(name: String,  colour: String): Fruit = Fruit(name)
}

Clearly, this assumes that colour is no longer required as an attribute of Fruit. (If it is required, it should not be deprecated.) It works by deprecating the factory method that creates a Fruit using a colour value.

If this doesn't work, can you explain why the field needs to be deprecated?

like image 35
Mike Allen Avatar answered Nov 15 '22 13:11

Mike Allen