Skip to content

Documentation for modify confusion #371

Description

@infinity0

I'm a bit confused about the documentation for modify in both Data.Vector and Data.Vector.Generic:

-- | Apply a destructive operation to a vector. The operation will be
-- performed in place if it is safe to do so and will modify a copy of the
-- vector otherwise.

It's unclear to me how we can possibly detect it is "safe" to perform the operation in-place given that, due to the type signature, the caller is free to pass the input again to another function. Indeed the implementation is just modify p = new . New.modify p . clone which looks like it does an unconditional copy.

Activity

  1. infinity0 commented on Mar 6, 2021

    @infinity0
    Author

    Documentation was originally added in a612079 by @rleshchinskiy

  2. lehins commented on Mar 6, 2021

    @lehins
    Contributor

    @infinity0 Without digging much into the exact proof why this works I will speculate destructive operation can be performed in place thanks to fusion, which is the only way to detect if it is safe to mutate immutable vector or not without relying on linear types.

    Here is a rewrite rule that will let us modify a vector without copy, which depends on how it was constructed and if it is being used multiple times or not:

    vector/Data/Vector/Generic.hs

    Lines 2259 to 2260 in 7ee4634

    "clone/new [Vector]" forall p.
    clone (new p) = p

    So if a vector was constructed with a function that relies on new then it should be mutated in place without copy.

    Whether this works or not as promised at all times or at all can only be confirmed with testing, core inspection and investigating rule firings. Not sure if anything along those lines have been done for modify function.

    With all this in mind I do agree that documentation is a bit confusing and could use some improvement.

  3. infinity0 commented on Sep 11, 2021

    @infinity0
    Author

    If I understand correctly, the fusion rules only express a subset of what safe situations are right? Namely, if the input Vector was itself just created by a call to new. However this won't always be the case, especially if the user is using this API with no knowledge of the fusion-specific aspects of Vector - there are lots of other, more common, ways of creating a Vector (e.g. from List) without having used the new function.

    So the documentation should be made clear regarding that - "Due to fusion RULES, the operation will be performed in place in a subset of the cases where it is safe to do so, namely if its input is statically known to the compiler to have been created with new."

  4. lehins commented on Sep 11, 2021

    @lehins
    Contributor

    There are plenty of rewrite rules that will change a pure function that you are using into a call to new, so you don't have to manually call new yourself in order to hit this optimization. For example the function you mentioned fromList will in fact be converted to a call to new:

    fromList xs = new (New.unstream (Bundle.fromList xs))

    Documenting this will not make things more clear, because it is an optimization. Note that if you compile with -O0 then destructive operation will never be performed in place because non of the rewrite rules will fire.

    I don't think you should take it too seriously and think of this as an optimization that compiler might or might not do it for you. So, documenting that would be good in my opinion: "There is an optimization, which in some case will do a destructive modification safely in place without extra copy"

  5. infinity0 commented on Sep 11, 2021

    @infinity0
    Author

    Yes fair enough, I didn't look into the details of how fromList is implemented; however I think my wording was fairly precise, "statically known to the compiler to have been created with new" - which covers the cases e.g. if the compiler doesn't know statically if it was created with fromList etc.

    I can understanding your point that documenting this detail about new is too specific however, and simply telling the reader "in some cases [etc]" I agree would be sufficient to communicate the situation clearly (and would solve this issue).

  6. Shimuuar commented on Sep 10, 2023

    @Shimuuar
    Contributor

    Fixed by #466

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions