scala-library-next icon indicating copy to clipboard operation
scala-library-next copied to clipboard

backwards-binary-compatible Scala standard library additions

Results 69 scala-library-next issues
Sort by recently updated
recently updated
newest added

## About this PR 📦 Updates [org.scala-lang:scala-library](https://github.com/scala/scala) from `2.13.13` to `2.13.14` 📜 [GitHub Release Notes](https://github.com/scala/scala/releases/tag/v2.13.14) - [Version Diff](https://github.com/scala/scala/compare/v2.13.13...v2.13.14) ## Usage ✅ **Please merge!** I'll automatically update this PR to resolve...

## About this PR 📦 Updates [org.scalacheck:scalacheck](https://github.com/typelevel/scalacheck) from `1.17.1` to `1.18.0` 📜 [GitHub Release Notes](https://github.com/typelevel/scalacheck/releases/tag/v1.18.0) - [Version Diff](https://github.com/typelevel/scalacheck/compare/v1.17.1...v1.18.0) ## Usage ✅ **Please merge!** I'll automatically update this PR to resolve...

Strict version of `Map.filterKeys`

[{"_id":"66470c362cfd0d66a80d5f50","body":"The [mapValues](https:\/\/www.scala-lang.org\/api\/2.13.13\/scala\/collection\/Map.html#mapValues[W](f:V=%3EW):scala.collection.MapView[K,W]) has the same promise in its deprecation and suffers the same performance issue. I did not need it yet, but I guess it should be added for completeness:\r\n\r\n> Use .view.mapValues(f). A future version will include a strict version of this method (for now, .view.mapValues(f).toMap).","issue_id":1715036973242,"origin_id":2066931388,"user_origin_id":6927223,"create_time":1713545106,"update_time":1713545125,"id":1715932214881,"updated_at":"2024-05-17T07:50:14.880000Z","created_at":"2024-05-17T07:50:14.880000Z"},{"_id":"66470c362cfd0d66a80d5f51","body":"Note that @OndrejSpanel you don't want the strict version IIUC, since that is what `m.view.filterKeys(p).toMap` does; that strict version is mostly to reduce the boilerplate.\r\n\r\nRather, it seems you want a lazy version that behaves like `m.view.filterKeys` but without loosing the `Map` type.","issue_id":1715036973242,"origin_id":2067035233,"user_origin_id":11336950,"create_time":1713548946,"update_time":1713548946,"id":1715932214886,"updated_at":"2024-05-17T07:50:14.885000Z","created_at":"2024-05-17T07:50:14.885000Z"},{"_id":"66470c362cfd0d66a80d5f52","body":"> Rather, it seems you want a lazy version that behaves like `m.view.filterKeys` but without loosing the `Map` type.\r\n\r\nIs that even possible? And if it is, I find it hard to believe any lazy solution would work well when chained multiple times, which is what my use case really is - like `(((map.filterKeys(p1) ++ aSeq1).filterKeys(p2) ++ aSeq2) ... .filterKeys(pN)) ++ aSeqN`\r\n\r\nMaybe what I really want is my workaround and I do not need this API at all. Maybe it is not possible to be more efficient?","issue_id":1715036973242,"origin_id":2067142855,"user_origin_id":6927223,"create_time":1713553657,"update_time":1713553744,"id":1715932214889,"updated_at":"2024-05-17T07:50:14.889000Z","created_at":"2024-05-17T07:50:14.889000Z"}] comment

[Map.filterKeys](https://www.scala-lang.org/api/2.13.13/scala/collection/Map.html#filterKeys(p:K=%3EBoolean):scala.collection.MapView[K,V]) is deprecated as the moment. Its deprecation message says: > Use .view.filterKeys(f). A future version will include a strict version of this method (for now, .view.filterKeys(p).toMap). The suggested `.view.filterKeys(p).toMap`...

Add `option.diff`

[{"_id":"67061c01ad3c4128c70e326a","body":"It can be even made a little bit more general:\r\n\r\n```scala\r\nimplicit class OptionValueOps[T](private val o: Option[T]) extends AnyVal {\r\n final def diff(that: Iterable[T]): Option[T] = {\r\n if (o.exists(that.contains)) None\r\n else o\r\n }\r\n}\r\n```\r\n\r\nNote: `o.exists(that.contains)` should be more performant than `that.exists(o.contains)` when `that.contains` is more efficient than `that.exists`, e.g. for `Set`.","issue_id":1715036973248,"origin_id":2123676924,"user_origin_id":6927223,"create_time":1716338887,"update_time":1716539085,"id":1728453633004,"updated_at":"2024-10-09T06:00:33.003000Z","created_at":"2024-10-09T06:00:33.003000Z"}] comment

Add `diff` to `Option` for a symmetry with `Seq`. Reference implementation: ```scala implicit class OptionValueOps[T](private val o: Option[T]) extends AnyVal { final def diff(that: Option[T]): Option[T] = { if (that.exists(o.contains))...

An obvious extension to `Option.when`. Reference implementation: ``` implicit class OptionOps(val o: Option.type) extends AnyVal { final def flatWhen[A](b: Boolean)(a: => Option[A]): Option[A] = if (b) a else None }...

Add randomElement

[{"_id":"66478c042308c3a9031a6abc","body":"This seems like the kind of thing that should go into a random number library, not a collections library. Seems awfully specialized. What if you want to choose `k` of `n` things? What if you want `k` things with replacement?\r\n\r\nThis seems to me just one of a variety of random sampling tasks that are useful. (Note that \"shuffle\" is also in this class, and that is provided in the random number library.)","issue_id":1715036973256,"origin_id":1175336396,"user_origin_id":2298644,"create_time":1657043574,"update_time":1657043574,"id":1715964932801,"updated_at":"2024-05-17T16:55:32.800000Z","created_at":"2024-05-17T16:55:32.800000Z"},{"_id":"66478c042308c3a9031a6abd","body":"Given my comments about a version receiving the random\/seed I understand your comments. I shouldn't have suggested that. However the simple version is very handy to have, at least these languages think so:\r\n\r\n- Ruby - the method is called [`sample`](https:\/\/apidock.com\/ruby\/v2_5_5\/Array\/sample).\r\n- Swift - is called randomElement and is available for [collections](https:\/\/developer.apple.com\/documentation\/swift\/collection\/randomelement(using:))\r\n- Rust - its called [`choose`](https:\/\/docs.rs\/rand\/0.7.2\/rand\/seq\/trait.SliceRandom.html#tymethod.choose)\r\n","issue_id":1715036973256,"origin_id":1175507062,"user_origin_id":5956311,"create_time":1657055836,"update_time":1657067125,"id":1715964932805,"updated_at":"2024-05-17T16:55:32.804000Z","created_at":"2024-05-17T16:55:32.804000Z"},{"_id":"66478c042308c3a9031a6abe","body":"Adding the method to `Random` would already be an improvement, although the ergonomics wouldn't be as good as adding it to Iterable.","issue_id":1715036973256,"origin_id":1176013698,"user_origin_id":5956311,"create_time":1657100622,"update_time":1657100622,"id":1715964932808,"updated_at":"2024-05-17T16:55:32.808000Z","created_at":"2024-05-17T16:55:32.808000Z"},{"_id":"66478c042308c3a9031a6abf","body":"Adding Python to languages that have this feature in their standard library.","issue_id":1715036973256,"origin_id":2027707941,"user_origin_id":28635807,"create_time":1711744244,"update_time":1711744244,"id":1715964932813,"updated_at":"2024-05-17T16:55:32.812000Z","created_at":"2024-05-17T16:55:32.812000Z"},{"_id":"66478c042308c3a9031a6ac0","body":"@Ichoran while I agree this should belong to `Random` rather than the collections framework, especially considering the need for a seed.\r\nWhile `shuffle` is general enough to represent this behavior, it feels unnecessarily expensive if you either just want a single element or want to keep getting multiple random elements when repetition is allowed.\r\nHaving said that, I guess the signature must either be `Option[A]` or throw if the collection is empty.","issue_id":1715036973256,"origin_id":2028085494,"user_origin_id":11336950,"create_time":1711808513,"update_time":1711808513,"id":1715964932817,"updated_at":"2024-05-17T16:55:32.817000Z","created_at":"2024-05-17T16:55:32.817000Z"},{"_id":"66478c042308c3a9031a6ac1","body":"@BalmungSan - I didn't mention `shuffle` because I thought you should implement selection with shuffle! I just mentioned it because it indicates that `Random` is a natural home for methods like these.\r\n\r\nIt's fine to add `Random.sample`. I was just suggesting it not be quite so specific. For instance, `r sample xs` might pick one element of `xs`, but `r.sample(xs, 5)` might pick five, and `r.sample(xs, 5, replace = true)` might pick five that could repeat.","issue_id":1715036973256,"origin_id":2028541173,"user_origin_id":2298644,"create_time":1711855697,"update_time":1711855697,"id":1715964932820,"updated_at":"2024-05-17T16:55:32.820000Z","created_at":"2024-05-17T16:55:32.820000Z"},{"_id":"66478c042308c3a9031a6ac2","body":"@Ichoran ah fair and apologies for the misunderstanding.\r\nYeah, that API feels great, the only missing thing would be the semantics of what happens if the `n` _(the number of requested elements)_ is bigger than `m` _(the size of the collection)_. Also, if the `1` case should be an overload with a different return type or just the default for `m` and get a collection of size `1`.\r\n\r\nBTW, my point was also that AFAIK this repo was not limited to only the collections framework, but the stdlib in general. And with plans for unfreezing the stdlib for future versions of **Scala 3** I guess is great to re-activate the discussions here.","issue_id":1715036973256,"origin_id":2028753310,"user_origin_id":11336950,"create_time":1711893356,"update_time":1711893356,"id":1715964932824,"updated_at":"2024-05-17T16:55:32.823000Z","created_at":"2024-05-17T16:55:32.823000Z"},{"_id":"66478c042308c3a9031a6ac3","body":"Yeah, rather than using a default argument, I'd recommend `sample(coll): A` but `sample(coll, n): Coll[A]` would make sense. In the spirit of safe operations by default, if you ask for `m` > `n` items, I'd say you would write `m` = `h` + `k` * `n` where `k` >= 1 and `h` < `n`, and return `k` shuffles of the original collection plus `h` randomly selected items. That is, you use everything at random; if you run out, everything is available again and you keep going.\r\n\r\nI'll add something like this to my kse3 library, and hopefully will report back if I run into any problems.\r\n","issue_id":1715036973256,"origin_id":2029143390,"user_origin_id":2298644,"create_time":1711946095,"update_time":1711946095,"id":1715964932827,"updated_at":"2024-05-17T16:55:32.826000Z","created_at":"2024-05-17T16:55:32.826000Z"},{"_id":"66478c042308c3a9031a6ac4","body":"@BalmungSan - I implemented something for arrays which generalizes fine to `IndexedSeq`. Then for things that aren't arrays, I implemented Algorithm L which doesn't even need to know how big the target is, but has a somewhat high constant cost (due to exponents\/logs being used every step).\r\n\r\nIt is live in kse3 maths 0.2.13, and I decorated the collections themselves with sample (in addition to putting it in the random number generator I wrote). No major hitches save for the usual ones when you want extension methods on collections (extension methods don't always understand the inheritance hierarchy).\r\n\r\nHere's a runnable example (using the variants that take a `given` random number source): https:\/\/scastie.scala-lang.org\/dS0La51UQxm9Gu3nRzWjAA\r\n\r\nAnyway, no significant problems!\r\n\r\nI ended up using `rng.sample(n)(coll)` for argument order for the method on the random number generator, but `coll.sample(n)(rng)` for the order on collection extension method.","issue_id":1715036973256,"origin_id":2057810750,"user_origin_id":2298644,"create_time":1713215226,"update_time":1713215262,"id":1715964932829,"updated_at":"2024-05-17T16:55:32.829000Z","created_at":"2024-05-17T16:55:32.829000Z"}] comment

Hey, I propose the method `randomElement` to be added to `Iterable`. This method returns a random element from the collection. On `Iterable` it can be (probably naively) implemented with: ```scala...

`tailOption` and `initOption`

[{"_id":"664616312308c3a903190bfd","body":"I agree that there are a couple of potentially useful methods here, but I don't think the name is quite right, since they shouldn't return `Option` -- they should return `Seq`, same as their `drop` counterparts. Not sure what to call them...","issue_id":1715036973262,"origin_id":1777589727,"user_origin_id":2184929,"create_time":1698164563,"update_time":1698164563,"id":1715869233693,"updated_at":"2024-05-16T14:20:33.692000Z","created_at":"2024-05-16T14:20:33.692000Z"},{"_id":"664616312308c3a903190bfe","body":"What you expect as `tailOption` \/ `initOption` can be done easily with `drop(1)` \/ `dropRight(1)`. See also https:\/\/stackoverflow.com\/questions\/42858306\/why-no-tailoption-in-scala","issue_id":1715036973262,"origin_id":1777651920,"user_origin_id":6927223,"create_time":1698166640,"update_time":1698166649,"id":1715869233699,"updated_at":"2024-05-16T14:20:33.698000Z","created_at":"2024-05-16T14:20:33.698000Z"},{"_id":"664616312308c3a903190bff","body":"@jducoeur why shouldn't they return Option[Seq]? i'd expect them to so i can e.g. use them in a (Option-based) for-comprehension.","issue_id":1715036973262,"origin_id":1777820689,"user_origin_id":547138,"create_time":1698172953,"update_time":1698172953,"id":1715869233705,"updated_at":"2024-05-16T14:20:33.705000Z","created_at":"2024-05-16T14:20:33.705000Z"},{"_id":"664616312308c3a903190c00","body":"You can, but is that really the useful behavior? While I don't strictly speaking object to an Option version, I'm hard-pressed to think of a time when I would want to use it. What I think I would more often want is a safe version of `tail` or `init`, which would return `Seq`. IMO, that's more naturally cognate to the intent of `headOption` -- the most convenient way to do this potentially-unsafe operation.\r\n\r\n(But obviously, this is subjective.)","issue_id":1715036973262,"origin_id":1777848421,"user_origin_id":2184929,"create_time":1698174014,"update_time":1698174014,"id":1715869233710,"updated_at":"2024-05-16T14:20:33.709000Z","created_at":"2024-05-16T14:20:33.709000Z"},{"_id":"664616312308c3a903190c01","body":"> You can, but is that really the useful behavior? \r\n\r\n@jducoeur in this context, not really. If it were returning something like `Option[NonEmptySeq]`, it would provide greater utility.","issue_id":1715036973262,"origin_id":1778040476,"user_origin_id":6216438,"create_time":1698181638,"update_time":1698181638,"id":1715869233714,"updated_at":"2024-05-16T14:20:33.713000Z","created_at":"2024-05-16T14:20:33.713000Z"},{"_id":"664616312308c3a903190c02","body":"I guess the deeper question is: what is the point of `tail` at all? `drop(1)` is the safe way to do it, and the return type is the same. Throwing an exception is almost always bad practice anyway. Yes, `List` is built out of heads and tails, but why is `tail` on everything and not just on `List`?\r\n\r\nIf you grant that `tail` was useful to begin with at all, _then_ the fact that it wasn't originally empty (even if the tail itself is) is potentially valuable. So if you want `tail` to exist, it's reasonable for `tailOption` to exist also, because this, unlike `drop(1)`, signals that there had been a head.\r\n\r\n","issue_id":1715036973262,"origin_id":1778088342,"user_origin_id":2298644,"create_time":1698183745,"update_time":1698183745,"id":1715869233718,"updated_at":"2024-05-16T14:20:33.717000Z","created_at":"2024-05-16T14:20:33.717000Z"},{"_id":"664616312308c3a903190c03","body":"I suppose, what _actually_ bothers me is the documentation?\r\n```scala\r\nval vector = Vector()\r\n\/\/ Collection's \"special\" accessors\r\nvector.head \/\/ Tells me it can throw\r\nvector.headOption \/\/ Should never throw from signature and docs\r\nvector.init \/\/ Throws but doesn't tell me\r\n\r\nvector.last \/\/ Tells me it can throw\r\nvector.lastOption \/\/ Should never throw from signature and docs\r\nvector.tail \/\/ Throws but doesn't tell me\r\n\r\n\/\/ Possibilities I see:\r\nextension [A](vector: Vector[A])\r\n \/\/ From signature, should never throw\r\n def initOption: Option[Vector[A]] = if vector.isEmpty then None else Some(vector.init)\r\n def tailOption: Option[Vector[A]] = if vector.isEmpty then None else Some(vector.tail)\r\n \/\/ From name, should never throw\r\n def initOrEmpty: Vector[A] = if vector.isEmpty then Vector.empty else vector.init\r\n def tailOrEmpty: Vector[A] = if vector.isEmpty then Vector.empty else vector.tail\r\nend extension\r\n\r\nvector.initOption\r\nvector.tailOption\r\nvector.initOrEmpty\r\nvector.tailOrEmpty\r\n```\r\n\r\n`tailOption` feels dumb, why have an `Option[Seq[T]]` when you can have a `Seq[T]`? But that's what I would expect `tail` to do, and `tail` crashes. I didn't realize about this exception until it crashed my program, and having an alternative would help me feel like I'm not about to re-invent the wheel. Calling `tail` shouldn't unexpectedly throw?\r\n\r\nEDIT: I made a dumb typo and flipped the `then` and `else` case by cause of \"brain fart\". I want to acknowledge this here to point out, these are the types of bug that slips in without anyone noticing.\r\n\r\n```scala\r\nval tailOrEmpty = if vector.isEmpty then vector.tail else Vector.empty\r\n\/\/ -- @julian-a-avar-c, 2024\r\n```\r\n\r\nI think my favorite implementation so far is `util.Try(vector.tail)` followed by `.toOption` or `.getOrElse(Vector.empty)`, since it's the one I can most easily read over without worrying about the implementation details. I don't think that's a good thing? `vector.tail` makes me feel the same way implicit nulls do. `Option(intOrNull).getOrElse(5)`.","issue_id":1715036973262,"origin_id":2027676423,"user_origin_id":28635807,"create_time":1711741970,"update_time":1711752331,"id":1715869233721,"updated_at":"2024-05-16T14:20:33.721000Z","created_at":"2024-05-16T14:20:33.721000Z"},{"_id":"664616312308c3a903190c04","body":"> I think my favorite implementation so far is `util.Try(vector.tail)` followed by `.toOption` or `.getOrElse(Vector.empty)`, since it's the one I can most easily read over without worrying about the implementation details. I don't think that's a good thing?\r\n\r\nNo, this is not a good thing.\r\n\r\nIf you want the whole list save the first element, safely, use `drop(1)`, not `tail`. `Try(vector.tail).toOption.getOrElse(Vector.empty)` is an extremely long and inefficient way to get the same behavior as `drop(1)`.\r\n\r\nLikewise with `dropRight(1)` vs `Try(vector.init).etc.etc.`\r\n\r\nIf `drop(1)` isn't an easy read for you, the best solution is to practice reading it until it is! The feature is already there, universally supported across all collection types. You just have to use it.\r\n","issue_id":1715036973262,"origin_id":2027805965,"user_origin_id":2298644,"create_time":1711753081,"update_time":1711753081,"id":1715869233726,"updated_at":"2024-05-16T14:20:33.725000Z","created_at":"2024-05-16T14:20:33.725000Z"},{"_id":"664616312308c3a903190c05","body":"@Ichoran I think it's useful to think in terms of `head` and `tail` (or `init` and `last`) in many situations from my experience. As such, I don't want them gone. That said, they break. So I think `headOption` and `lastOption` are both good ideas. If maybe with different implementations and names.\r\n\r\nIf your thoughts are to tough it out and use `drop(1)` because it's already there (lemme be snarky and say that `tail` is already there also :smiling_imp:), then please consider that the point of this thread (from the top) was to acknowledge their existence, but to share the shortcomings of `tail` and family since we are getting ready for the _next_ Scala standard library. With your presented criteria, we should be getting rid of\/deprecating `headOption`, and telling everyone to use `vector.take(1)`.\r\n\r\nIn the case adding `vector.tailOption` or alternatives is unfeasible for technical or not reason, and since we already acknowledge `tail`'s value as it stands inside of the current standard library), I would suggest adding documentation to `tail` to indicate its exceptions (Which I have no idea what that looks like, `NoTailException`? Right now we are getting `java.lang.ExceptionInInitializerError`). And also a comment highlighting that you can use `_.drop(1)` instead as is done in some methods of the library already.\r\n\r\n`tail` and `init` have already proven themselves. They are used and useful as far as I am aware.\r\n\r\n---\r\n\r\nLastly and for completeness, I would like to acknowledge with you that `Try(vector.tail).getOrElse(Vector.empty)` is not a good idea. **But what I was referring to before**, is that I also don't think it's a good idea that when thinking in terms of heads, tails, inits, and lasts, that the monstrosity from before is the easiest to write and read and least error prone way of writing if both of those things are of the top-most importance. And _that_ isn't a good thing.\r\n\r\nI don't think anyone here is advocating for `Try(vector.tail).getOrElse(Vector.empty)` (except _maybe_ the author of the SO answer, but even he\/she\/they mentioned other methods being better fit), it might be easier to read when you don't know that `vector.tail` can fail, and in some non-performance-intensive places it might even be worth it, because `vector.tail` could crash your program, and it's not intuitive or documented.\r\n\r\n---\r\n\r\nLet me know if any of this sounds appealing, and if I can be of help.","issue_id":1715036973262,"origin_id":2027822812,"user_origin_id":28635807,"create_time":1711755399,"update_time":1711757818,"id":1715869233729,"updated_at":"2024-05-16T14:20:33.728000Z","created_at":"2024-05-16T14:20:33.728000Z"},{"_id":"664616312308c3a903190c06","body":"I agree that for completeness `tailOption` and `initOption` are a good idea, as safe alternatives to the unsafe `tail` and `init`, to parallel `headOption` and `lastOption`. And certainly the `tail` and `init` docs should say that they will throw an exception if the collection is empty!\r\n\r\nBut what I _don't_ agree with is that someone reaching for `Try(xs.tail).toOption.getOrElse(Vector.empty)` instead of `drop(1)` indicates anything but that they're along the path of their process of learning Scala. It _does_ take a while to learn the standard library for collections; it's extremely versatile but this does mean it's not small. It _isn't_ the easiest or clearest way to get the desired behavior except when someone has partly learned the collections API (if they were comfortable with it, they'd `drop(1)`) and partly learned the Try interface (if they were comfortable with that, they wouldn't add the superfluous `toOption`; `Try` has `getOrElse` itself).\r\n\r\nI think we should structure the documentation to help people who are learning. However, I _don't_ think we should structure the library to \"help\" people who are trying, because of lack of familiarity, to build from the parts they know functionality that already exists. Rather, we should help them learn the functionality that exists.\r\n\r\n(Note: The reason to use `tailOption` is not if you immediately want to `getOrElse(Vector.empty)` it. It's if you want to use `Option` to handle the conditional logic about what to do if there is a tail and if there is not.)\r\n","issue_id":1715036973262,"origin_id":2027842335,"user_origin_id":2298644,"create_time":1711758312,"update_time":1711758376,"id":1715869233732,"updated_at":"2024-05-16T14:20:33.731000Z","created_at":"2024-05-16T14:20:33.731000Z"},{"_id":"664616312308c3a903190c07","body":"> But what I don't agree with is that someone reaching for `Try(xs.tail).toOption.getOrElse(Vector.empty)` instead of `drop(1)` indicates anything but that they're along the path of their process of learning Scala\r\n\r\nOk... Full stop... Moving on...\r\n\r\n---\r\n\r\nI'm aware of `tailOption` marking if there was or not a last element, since `Seq[T]` would not as opposed to `tailOrEmpty`. Thank you for letting me know regardless, and please read the code I wrote?\r\n\r\nAs a side note, I believe `tailOption` is a worse design, since for knowing if there is a head, a pattern match might be more idiomatic. But `tailOrEmpty` says \"I want to use the tail and I don't know if it exists so give me an empty instead\" which is what `tail` does if there is only one element.\r\n\r\n---\r\n\r\nI suppose what I'm asking is:\r\n\r\nWhat are the reasons to avoid this design? And what are the reasons to add it?\r\n\r\nAs I see it, there are only good things from `tailOption` or `tailOrEmpty`. And I also want to help Scala in any way I can. An intuitive standard library makes an intuitive language.","issue_id":1715036973262,"origin_id":2027846514,"user_origin_id":28635807,"create_time":1711759038,"update_time":1711759266,"id":1715869233734,"updated_at":"2024-05-16T14:20:33.734000Z","created_at":"2024-05-16T14:20:33.734000Z"},{"_id":"664616312308c3a903190c08","body":"In fact, I would say I'm advocating for `tail` failing if there is a single element in a collection, but I understand that would be shocking for existing users, AND would break compatibility.","issue_id":1715036973262,"origin_id":2027848028,"user_origin_id":28635807,"create_time":1711759335,"update_time":1711759364,"id":1715869233737,"updated_at":"2024-05-16T14:20:33.737000Z","created_at":"2024-05-16T14:20:33.737000Z"},{"_id":"664616312308c3a903190c09","body":"If you're interested, and I'm suggesting here once more, perhaps if we wanted to more closely model the `tailOption` meaning, \"get me the tail or nothing\" would be more like:\r\n\r\n```scala\r\nextension [A](vector: Vector[A])\r\n def tailOnlyOption: Option[Vector[A]] = if vector.length < 2 then None else Some(vector.tail)\r\n```\r\nThat is to say, if there is 0 or 1 elements (no tail), return `None`, else the tail, as opposed to `Some(Vector.empty)` if there is a head. But I advocate for `tailOrEmpty`.","issue_id":1715036973262,"origin_id":2027854325,"user_origin_id":28635807,"create_time":1711760507,"update_time":1711763079,"id":1715869233740,"updated_at":"2024-05-16T14:20:33.739000Z","created_at":"2024-05-16T14:20:33.739000Z"},{"_id":"664616312308c3a903190c0a","body":"> In fact, I would say I'm advocating for `tail` failing if there is a single element in a collection, but I understand that would be shocking for existing users, AND would break compatibility.\r\n\r\nPart of learning a new language is getting used to the standard ways to do things. Maybe it makes more sense to you that `tail` only works if there is a _nonempty_ tail, but everyone used to Scala understands it as any kind of tail, including an empty one (but it must _be_ a tail: there must be a head). People have developed the intuition that empty collections are fine, and that head\/tail are low-level risky operations while `drop(1)` or `match` are higher-level safe operations (if you cover all the branches of the match, which the compiler will warn you about if you don't).\r\n\r\nI agree with you that one _could_ define things differently. It's not insensible a priori. It just isn't how Scala works, and I don't agree that it's more intuitive in general.\r\n\r\nI mean, you could also argue that you should index from 1 in Scala instead of 0. Who starts counting at 0, anyway?! R and Matlab do, in fact, index from 1. But most languages, including Scala (and Java, and Python, and C\/C++, and JavaScript) index from 0. If you wanted a new low-level operation `keep(start, end)` that would throw an exception if either bound was wrong, but `start` and `end` were 1-indexed and inclusive end because it's \"more intuitive\", it would, in Scala, confuse the heck out of everyone because the intuition is for 0-indexing and exclusive end.\r\n\r\nSo, some things can be made more intuitive within the context of the language, but mostly by making the patterns more regular. If you have `take` and `takeWhile` and `takeRight`, but not `takeRightWhile`, that's kind of a glitch in the pattern. Likewise, to have `head` (unsafe) and `headOption` for safety and monadic handling, but not `tail` with `tailOption` for safety and monadic handling, is a glitch in the pattern and it's more intuitive if it's fixed. However, it's less intuitive if for `tailOption`, but nothing else, the tail has to be nonempty. That _doesn't_ make things more regular, it makes them _less_ regular, breaking intuition for anyone who has taken enough time to develop it. And to have `nonEmptyTailOption` is possible, but the collections library is already huge and once you start having non empty collections you start wanting type support for it (otherwise the compiler can't help you keep track of when something is there and when it might not be), and then you end up with something like `NonEmptyList` which [Cats already has](https:\/\/typelevel.org\/cats\/datatypes\/nel.html)--so just use Cats if you want to work that way!\r\n\r\nIf you make your own language or even your own library, you can make these decisions anew. But existing well-established regularities should be left alone, and the bar to add new variants should be quite high--mostly finding very common use cases that are only very awkwardly supported by the existing library.\r\n\r\n(There are a still a surprising number of these, despite the already-large library.)\r\n\r\n> But `tailOrEmpty` says \"I want to use the tail and I don't know if it exists so give me an empty instead\" which is what `tail` does if there is only one element.\r\n\r\nBut that has the behavior of `drop(1)`. We don't need another way to spell it. If we were going to spell it differently, we should probably spell it `dropOne`. But why? `drop(1)` is pretty clear, once you know how `drop` works.\r\n","issue_id":1715036973262,"origin_id":2027879966,"user_origin_id":2298644,"create_time":1711764557,"update_time":1711764557,"id":1715869233743,"updated_at":"2024-05-16T14:20:33.742000Z","created_at":"2024-05-16T14:20:33.742000Z"},{"_id":"664616312308c3a903190c0b","body":"I see, thank you for your responses. I suppose my vision was shortsighted.","issue_id":1715036973262,"origin_id":2028474397,"user_origin_id":28635807,"create_time":1711834537,"update_time":1711834537,"id":1715869233747,"updated_at":"2024-05-16T14:20:33.746000Z","created_at":"2024-05-16T14:20:33.746000Z"}] comment

For symmetry. Once in a while I need them because the sequence might be empty. `Seq().tail` and `Seq().init` throw errors. Ideally I want those two to be corrected and return...

Add SeqSet

[{"_id":"67061befad3c4128c70e325c","body":"Note: without adding new implementations for the new traits, this depends on #21 ","issue_id":1715036973273,"origin_id":737649200,"user_origin_id":7505383,"create_time":1606967758,"update_time":1606968519,"id":1728453615089,"updated_at":"2024-10-09T06:00:15.089000Z","created_at":"2024-10-09T06:00:15.089000Z"},{"_id":"67061befad3c4128c70e325d","body":"thoughts on this change? (\ud83d\udc4d in favour, \ud83d\udc4e against)","issue_id":1715036973273,"origin_id":737649871,"user_origin_id":7505383,"create_time":1606967919,"update_time":1606968432,"id":1728453615095,"updated_at":"2024-10-09T06:00:15.094000Z","created_at":"2024-10-09T06:00:15.094000Z"},{"_id":"67061befad3c4128c70e325e","body":"So, we would have `LinkedHashSet` as a concrete subtype of `SeqSet`?","issue_id":1715036973273,"origin_id":738157132,"user_origin_id":332812,"create_time":1607016128,"update_time":1607016128,"id":1728453615098,"updated_at":"2024-10-09T06:00:15.098000Z","created_at":"2024-10-09T06:00:15.098000Z"},{"_id":"67061befad3c4128c70e325f","body":"yes, although it will take some fiddling to make that actually work in scala-library-next (if it's not final, we might be able to subtype it with a mixin?)","issue_id":1715036973273,"origin_id":738186132,"user_origin_id":7505383,"create_time":1607018934,"update_time":1607018947,"id":1728453615102,"updated_at":"2024-10-09T06:00:15.101000Z","created_at":"2024-10-09T06:00:15.101000Z"},{"_id":"67061befad3c4128c70e3260","body":"We'd want `VectorSet` as well: #168","issue_id":1715036973273,"origin_id":1832057939,"user_origin_id":161079,"create_time":1701269904,"update_time":1701269904,"id":1728453615107,"updated_at":"2024-10-09T06:00:15.106000Z","created_at":"2024-10-09T06:00:15.106000Z"}] comment

Add `SeqSet`, mirroring `SeqMap`.

enhancement
library:collections
status:pending

Add `VectorSet` (to correspond with `VectorMap`)

[{"_id":"66470c382cfd0d66a80d5f63","body":"this is part of #22 ","issue_id":1715036973282,"origin_id":1832057526,"user_origin_id":161079,"create_time":1701269891,"update_time":1701269891,"id":1715932216196,"updated_at":"2024-05-17T07:50:16.196000Z","created_at":"2024-05-17T07:50:16.196000Z"}] comment

afaict there isn't any reason why this is missing. (we have both `LIstSet` and `ListMap`)

Add mapWithState

[{"_id":"67061c29eedbdc0cb30c905b","body":"Id do this with a fold normally..And IMO the final state value needs to be\nexposed..\n\nOn Sat., 21 May 2022, 10:41 am Luis Miguel Mej\u00eda Su\u00e1rez, <\n***@***.***> wrote:\n\n> The signature would be something like:\n>\n> def mapWithState[S, B](init: S)(f: (S, A) => (S, B)): Col[B]\n>\n> Is not as common as mapWithIndex but is kind of handy and is very hard to\n> implement generically without much boilerplate.\n>\n> \u2014\n> Reply to this email directly, view it on GitHub\n> <https:\/\/github.com\/scala\/scala-library-next\/issues\/122>, or unsubscribe\n> <https:\/\/github.com\/notifications\/unsubscribe-auth\/AAAXJZGCGN5PUGC6N3UYHGLVLAWLDANCNFSM5WQ747RA>\n> .\n> You are receiving this because you are subscribed to this thread.Message\n> ID: ***@***.***>\n>\n","issue_id":1715036973288,"origin_id":1133495505,"user_origin_id":95460,"create_time":1653096838,"update_time":1653096838,"id":1728453673408,"updated_at":"2024-10-09T06:01:13.408000Z","created_at":"2024-10-09T06:01:13.408000Z"},{"_id":"67061c29eedbdc0cb30c905c","body":"> Id do this with a fold normally\r\n\r\nThe thing is that now you have to construct the new collection by yourself which is redundant and error-prone but also it may be more inefficient than the underlying `map`\r\n\r\n> And IMO the final state value needs to be exposed\r\n\r\nYeah, that is a good idea.\r\n\r\nPS: For the record, **fs2** has this function, is called `mapAccumulate`\r\nAnd I am creating a PR to add it to **cats**.","issue_id":1715036973288,"origin_id":1133496927,"user_origin_id":11336950,"create_time":1653097419,"update_time":1653097419,"id":1728453673412,"updated_at":"2024-10-09T06:01:13.411000Z","created_at":"2024-10-09T06:01:13.411000Z"},{"_id":"67061c29eedbdc0cb30c905d","body":"mapAccululate or mapAccumulation or statefulMap","issue_id":1715036973288,"origin_id":1703881786,"user_origin_id":501740,"create_time":1693672001,"update_time":1693672001,"id":1728453673415,"updated_at":"2024-10-09T06:01:13.415000Z","created_at":"2024-10-09T06:01:13.415000Z"},{"_id":"67061c29eedbdc0cb30c905e","body":"Just mentioned this here: https:\/\/users.scala-lang.org\/t\/idiomatic-map-combined-with-fold\/9628, which lead me here. Had the need for this on several occasions.","issue_id":1715036973288,"origin_id":1819605041,"user_origin_id":1765601,"create_time":1700505372,"update_time":1700505372,"id":1728453673422,"updated_at":"2024-10-09T06:01:13.421000Z","created_at":"2024-10-09T06:01:13.421000Z"}] comment

The signature would be something like: ```scala def mapWithState[S, B](init: S)(f: (S, A) => (S, B)): Col[B] ``` Is not as common as `mapWithIndex` but is kind of handy and...