-
Notifications
You must be signed in to change notification settings - Fork 21
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
Support 'without' for Anonymous Records #762
Comments
Would you be able to chain multiple
|
I would expect a semicolon-delimited list of labels, sort of an inverse to what you can do today: let a = {| X = 1; Y = 2; Z = 3|}
let b = {| a with A = 3; B = 4; C = 12 |} So it would probably look like: let _ = {| a without Foo; Bar |} |
What are your thoughts on allowing combining
|
It might be worth noting that in Elm:
|
RE: https://elm-lang.org/blog/compilers-as-assistants#simplified-records The syntax in Elm was actually really nice and intuitive. |
@jwosty I think combining would probably be out of scope - works for simple stuff, but there'd have to be some rule for determining what subsequent |
I think I'm basically OK with this - it is true that it is no worse than Note this would make |
Just to clarify, for backwards compat, would we still compile something like this? let without x = ()
without 12 |
to the extreme: let y = {| x without without |}
|
Correct, I can't think of a way for it to collide unless we explicitly took a breaking change here. |
Don't be shy :)
|
I was going to propose More seriously, we don't have contextual keywords yet, do we? This feels like too minor a feature to introduce such a major concept. |
perhaps because |
I guess
|
Would there be an issue with a contexual keyword like this? I don't think it's too crazy. Generally I don't think I'd like |
I think |
It feels hard TBH |
I'm little |
perhaps this would fly, though it's a bit weird too:
or
or for the unix heads (joke)
|
Can someone describe why this is needed? What are the applications or existing use-cases / scenarios? |
I think the OP explains why - basically, if you can create a new anonymous with extra fields, it seems reasonable to also support removing a field. I don't think it's crucial at all, it's just a reasonable completion of the anon record feature within the criteria of the original RFC. |
Yes I understand what the feature should do. I'm asking because you could also "solve" this another way: Why not allow Anonymous Records at places where fewer fields are required? let f {| X = x |} = x
f {| X = 1; Y = 2 |} // 1 This obviously needs to solve how we can represent this in IL and also some other corner cases, but it would remove the need to explicitly remove fields. However, for this to be useful you need to know what the feature use-cases are (which hasn't been answered) |
Im all for more record row polymorphism type features, it is really curious that the feature was almost never used in Elm though. |
@matthid This was filed as a suggestion after speaking with @Rickasaurus and his team at an F# meetup. The "drop a column" use case is applicable to any scenario where you'd do the same with Pandas/Python. It is also a dual to the "add a column" functionality you can do now with no apparent downside aside from just being another thing you can learn. Your comment - effectively structural subtyping - was also brought up as highly relevant to that space, but it's explicitly called out as a non-goal here: https://github.com/fsharp/fslang-design/blob/master/FSharp-4.6/FS-1030-anonymous-records.md#design-principle-no-structural-subtyping So the issues listed in the RFC would have to be resolved for that to progress. Though the two suggestions are sort of related, but the ability to "drop a column and move on" seems distinct enough from structural subtyping to warrant its own issue. |
Yes, drop-a-column may well get used in places where there is no strongly-typed consumer with the new set of columns made explicit. @cartermp One criticism of these features might be that these operations have no corresponding things in the type algebra, e.g. given |
@yatli Please refer to the RFC here: fsharp/fslang-design#370 |
@yatli, x and y are the same types, but y has a different value for foo. Variable z is a new type, without the field foo. |
@cartermp thanks, I think it answers my latter question. @abelbraaksma that’s a gotcha, we’ve got different assumptions here—whether the type of x has foo already or not. |
If I'm not mistaken, the identity of an anonymous record is determined by its defining assembly and its field names and types. So given your example: let x = {...}
let y = {| x with foo = 1 |}
let z = {| y without foo |}
|
thanks @Tarmil, imho this kind of detail should be clarified, and written into the RFC. I was assuming that every mutated anonymous record will produce a different type, and two mutations have different types even if the type signature appears to be the same:
|
@yatli Note that this is already covered in the existing anonymous records RFC. If you feel specific sections need clarification, please comment on the PR - it's easier to address that way. |
I'm super hyped for that feature because it allows me to do the same out of the box what this library in the Scala World called type DomainEventA = {| A: int; B : float; CreatedAt: System.DateTime |}
type DomainEventB = {| A: int; CreatedAt: string |}
module DomainEventA =
let toDomainEventB(a: DomainEventA ) : DomainEventB =
{| {| a without B |} with CreatedAt = a.CreatedAt |> string |} |} How is the syntax intented to be used with mixing |
@realvictorprm Please refer to the RFC pull request here: fsharp/fslang-design#370 I believe it addresses your question |
You're right. I'm very pleased with the RFC, maybe I should try creating a draft implementation for that 🤔 |
We would use this it tailor an API response object based on permissions available to the requestor. For example the response pipeline might have a function |
Then this feature won't help you as you won't know it at compile-time. |
I was thinking of something like this:
|
I'm looking forward to this feature but I'm not a fan of What about an less-common antonym like Side note, I'm not sure why this wasn't done much in Elm but I find the syntax unclear at a glance. |
Just saw in the discussion of my syntax proposal in #492 (where I said "if #762 introduces the
|
I tend to agree with @rmunn. Aesthetically |
Yeah, |
From the top of my head: what if we move in another direction and specify fields to include, something like this? let r1 = {| A = 1; B = ""; C = true |}
let r2 = {| r1 with A, B |}
// or
let r3 = {| r1 with A; B |} It won't require adding another keyword or using the |
@auduchinok There's also a functionality difference between your proposal and the let frontendUser = {| backendUser without password |}
// Or
let frontendUser2 = {| backendUser with firstName, lastName, email |} If |
I'm playing with it now, and yeah, it really looks weird :) Maybe it will be a good idea to iterate on it again. However, the idea was not to save characters, but to not use currently valid identifier ( |
The more I think about it, the more I like
|
Can we move discussion here? fsharp/fslang-design#616 (comment) The RFC is merged so there's not much to talk about in this thread. |
Shall this issue be locked and closed (since RFC is approved and merged) in favour of discussion? |
Nah, we can just keep it as-is for now. I think the tendency is to close only when the feature is merged and in preview. |
Another idea - what about this syntax (association with destructors) let x = {| A =1; B = 2 |}
let y = {| x with ~A |} |
wondering if with considerations around #1253, and this, we could have way to remove arbitrary field for any anonymous record, with inline function, rather than having to define it for a specific type. let inline justBe (be: {|manner:'a; ...|}) = {| be without manner |} |
I propose we support expressions of the following:
That is, being able to construct a new anonymous record that is a subset of another one.
The existing way of approaching this problem in F# is to manually construct
a'
:Pros and Cons
The advantages of making this adjustment to F# are:
The disadvantages of making this adjustment to F# are :
Extra information
Here's what the RFC says about this:
However, Anonymous Records already support
{| x with SomethingElse = foo |}
to construct a new AR that has more fields than the one it was constructed from. This means that the middle point is already sort of violated, since you cannot reproduce this with record types.Estimated cost (XS, S, M, L, XL, XXL): S-M
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
The text was updated successfully, but these errors were encountered: