Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@erikvanoosten
Copy link
Contributor

This change brings Refs on par with AtomicInteger and AtomicLong by implementing methods like getAndIncrement and incrementAndGet directly on Ref.

By using the Numeric type class, the new methods are actually supported for all numeric types.

This change brings `Ref`s on par with `AtomicInteger` and `AtomicLong` by implementing methods like `getAndIncrement` and `incrementAndGet` directly on Ref.

By using the `Numeric` type class, the new methods are actually supported for all numeric types.
@hearnadam
Copy link
Collaborator

I suspect these are better fitting as extension methods for specific types... Using these methods will introduce interface dispatch through Numeric and boxing via an unspecialized Ref. We should probably consider ways to introduce specialization without boxing via concrete classes...

@kyri-petrou
Copy link
Contributor

@hearnadam I agree although I think that it might be better to do what you're proposing as a separate piece of work. It will actually be really good to have concrete classes that utilize AtomicInt, AtomicLong and other AtomicX under the hood for primitives.

AFAICT the changes in this PR should be backwards compatible, where we can simply ignore the implicit Numeric in the specialized implementations.

@hearnadam
Copy link
Collaborator

Can these be extension methods instead?

@kyri-petrou
Copy link
Contributor

Can these be extension methods instead?

If we have them as extension methods we won't be able to override them when we end up implementing via concrete classes. Or maybe I'm missing something?

* Atomically increments the current value of the `Ref` by 1, returning the
* value immediately before modification.
*/
final def getAndIncrement(implicit num: math.Numeric[A], trace: Trace): UIO[A] =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it wise to mark them as final? I suppose a specialized version won't have the implicit argument anyway, so maybe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making them non-final is fully backwards compatible, so maybe we can start with having them as final and we can change them when needed

@erikvanoosten
Copy link
Contributor Author

Is there anything I can do?

@kyri-petrou
Copy link
Contributor

Is there anything I can do?

I was just waiting to see if there are any more comments before merging. @hearnadam do you have anything to add to this comment?

@hearnadam
Copy link
Collaborator

I don't think it's possible to avoid the boxing without deferred in-lining which I was unable to make work even in Scala 3 only.

The concrete class can at least override those methods, so you're correct that's a better approach.

@kyri-petrou
Copy link
Contributor

kyri-petrou commented Nov 28, 2024

I don't think it's possible to avoid the boxing without deferred in-lining which I was unable to make work even in Scala 3 only.

The concrete class can at least override those methods, so you're correct that's a better approach.

@hearnadam I think there are patterns in Scala 3 that could avoid the boxing, e.g.,:

extension (ref: Ref[Int]) {
  @targetName("getAndIncrementInt")
  def getAndIncrement: UIO[Int] = ref.getAndUpdate(_ + 1)
}

extension (ref: Ref[Long]) {
  @targetName("getAndIncrementLong")
  def getAndIncrement: UIO[Long] = ref.getAndUpdate(_ + 1)
}

But yeah can't think of a way to make this cross-compile to Scala 2 since we're lacking the targetName annotation

@kyri-petrou kyri-petrou merged commit d441ab0 into zio:series/2.x Nov 28, 2024
18 checks passed
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

Successfully merging this pull request may close these issues.

4 participants