Is there already or can I declare a more pipe friendly upcast?











up vote
6
down vote

favorite
1












I want to be able to just



let upcast'<'T,'TResult when 'T :> 'TResult> (y:'T) = y |> upcast



However, that then constrains 'T to be 'TResult instead of it being something that can be cast to 'TResult



I know I can




  1. |> fun x -> x :> 'TResult


  2. |> fun x -> upcast x


  3. |> fun x -> x :> _



but then if I'm doing anything else on that line I have to go back and put () around the fun x -> upcast x or it thinks what I'm doing is part of the fun x function.



can I define or does there exist a way to be able to



|> upcast |> doesn't work



|> ( ( :> ) 'TResult) doesn't work and is messy



edit
In response to Thomas Petricek - minimal failing auto-upcast sample:



module Test =
let inline f'<'t>():IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
|> fun x -> x :> IReadOnlyCollection<_>

let inline f<'t> () :IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection









share|improve this question
























  • in the edit, the 2nd example fails, while the first works
    – Maslow
    Nov 9 at 16:53















up vote
6
down vote

favorite
1












I want to be able to just



let upcast'<'T,'TResult when 'T :> 'TResult> (y:'T) = y |> upcast



However, that then constrains 'T to be 'TResult instead of it being something that can be cast to 'TResult



I know I can




  1. |> fun x -> x :> 'TResult


  2. |> fun x -> upcast x


  3. |> fun x -> x :> _



but then if I'm doing anything else on that line I have to go back and put () around the fun x -> upcast x or it thinks what I'm doing is part of the fun x function.



can I define or does there exist a way to be able to



|> upcast |> doesn't work



|> ( ( :> ) 'TResult) doesn't work and is messy



edit
In response to Thomas Petricek - minimal failing auto-upcast sample:



module Test =
let inline f'<'t>():IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
|> fun x -> x :> IReadOnlyCollection<_>

let inline f<'t> () :IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection









share|improve this question
























  • in the edit, the 2nd example fails, while the first works
    – Maslow
    Nov 9 at 16:53













up vote
6
down vote

favorite
1









up vote
6
down vote

favorite
1






1





I want to be able to just



let upcast'<'T,'TResult when 'T :> 'TResult> (y:'T) = y |> upcast



However, that then constrains 'T to be 'TResult instead of it being something that can be cast to 'TResult



I know I can




  1. |> fun x -> x :> 'TResult


  2. |> fun x -> upcast x


  3. |> fun x -> x :> _



but then if I'm doing anything else on that line I have to go back and put () around the fun x -> upcast x or it thinks what I'm doing is part of the fun x function.



can I define or does there exist a way to be able to



|> upcast |> doesn't work



|> ( ( :> ) 'TResult) doesn't work and is messy



edit
In response to Thomas Petricek - minimal failing auto-upcast sample:



module Test =
let inline f'<'t>():IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
|> fun x -> x :> IReadOnlyCollection<_>

let inline f<'t> () :IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection









share|improve this question















I want to be able to just



let upcast'<'T,'TResult when 'T :> 'TResult> (y:'T) = y |> upcast



However, that then constrains 'T to be 'TResult instead of it being something that can be cast to 'TResult



I know I can




  1. |> fun x -> x :> 'TResult


  2. |> fun x -> upcast x


  3. |> fun x -> x :> _



but then if I'm doing anything else on that line I have to go back and put () around the fun x -> upcast x or it thinks what I'm doing is part of the fun x function.



can I define or does there exist a way to be able to



|> upcast |> doesn't work



|> ( ( :> ) 'TResult) doesn't work and is messy



edit
In response to Thomas Petricek - minimal failing auto-upcast sample:



module Test =
let inline f'<'t>():IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
|> fun x -> x :> IReadOnlyCollection<_>

let inline f<'t> () :IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection






f#






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 9 at 16:45

























asked Nov 8 at 18:39









Maslow

12.5k1482167




12.5k1482167












  • in the edit, the 2nd example fails, while the first works
    – Maslow
    Nov 9 at 16:53


















  • in the edit, the 2nd example fails, while the first works
    – Maslow
    Nov 9 at 16:53
















in the edit, the 2nd example fails, while the first works
– Maslow
Nov 9 at 16:53




in the edit, the 2nd example fails, while the first works
– Maslow
Nov 9 at 16:53












2 Answers
2






active

oldest

votes

















up vote
5
down vote













As far as I know, specifying the kind of constraint between 'T and 'TResult is not possible. There is a related question about this with links to more information and a feature request.



That said, I wonder why do you need this? The F# compiler is able to insert upcasts automatically, even when using pipes, so if you want to do this as part of a longer pipe, it should not be needed. Here is a simple illustration:



type Animal = interface end
type Dog = inherit Animal

let makeDog () = { new Dog }
let consumeAnimal (a:Animal) = 0

makeDog () |> consumeAnimal


I guess you might need pipe-able upcast if you wanted to have it at the end of the pipeline, but then I'd just do the upcast on a separate line. Or is your question motivated by some more complicated cases where the implicit upcast does not work?



EDIT 1: Here is a minimal example using ReadOnlyCollection and IReadOnlyList which works:



let foo () : System.Collections.ObjectModel.ReadOnlyCollection<int> = failwith "!"
let bar (x:System.Collections.Generic.IReadOnlyList<int>) = 0

foo() |> bar


EDIT 2: To comment on the update - the problem here is that automatic upcasts are only inserted when passing arguments to functions, but in the second example, the type mismatch is between the result of the pipe and the return type of the function. You can get that to work by adding an identity function of type IReadOnlyCollection<'T> -> IReadOnlyCollection<'T> to the end of the pipe:



let inline f<'t> () :IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
|> id<IReadOnlyCollection<_>>


This works, because now the upcast is inserted automatically when passing the argument to the id function - and this then returns a type that matches with the return type of the function.






share|improve this answer























  • Yeah auto upcast from ReadOnlyCollection<_> to IReadOnlyList<_> doesn't seem to work
    – Maslow
    Nov 9 at 4:56












  • @Maslow My trivial test (see edit) worked - it would be interesting to see a small counter-example for this - I suspect there is one, because the auto-upcasts are not perfect, but I'm not sure what exactly it needs to look like...
    – Tomas Petricek
    Nov 9 at 14:51










  • edited to add the sample
    – Maslow
    Nov 9 at 16:46










  • dammit, I was in an edit frenzy on the question and edited your answer on accident, and I'm not sure I can undo that
    – Maslow
    Nov 9 at 16:50












  • @Maslow Thanks for the example! This is actually a bit different situation - see my Edit 2!
    – Tomas Petricek
    Nov 10 at 23:43


















up vote
0
down vote













much simpler and unexpected



let inline f2<'t>() : IReadOnlyCollection<'t> = 
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
:> _





share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53214150%2fis-there-already-or-can-i-declare-a-more-pipe-friendly-upcast%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    5
    down vote













    As far as I know, specifying the kind of constraint between 'T and 'TResult is not possible. There is a related question about this with links to more information and a feature request.



    That said, I wonder why do you need this? The F# compiler is able to insert upcasts automatically, even when using pipes, so if you want to do this as part of a longer pipe, it should not be needed. Here is a simple illustration:



    type Animal = interface end
    type Dog = inherit Animal

    let makeDog () = { new Dog }
    let consumeAnimal (a:Animal) = 0

    makeDog () |> consumeAnimal


    I guess you might need pipe-able upcast if you wanted to have it at the end of the pipeline, but then I'd just do the upcast on a separate line. Or is your question motivated by some more complicated cases where the implicit upcast does not work?



    EDIT 1: Here is a minimal example using ReadOnlyCollection and IReadOnlyList which works:



    let foo () : System.Collections.ObjectModel.ReadOnlyCollection<int> = failwith "!"
    let bar (x:System.Collections.Generic.IReadOnlyList<int>) = 0

    foo() |> bar


    EDIT 2: To comment on the update - the problem here is that automatic upcasts are only inserted when passing arguments to functions, but in the second example, the type mismatch is between the result of the pipe and the return type of the function. You can get that to work by adding an identity function of type IReadOnlyCollection<'T> -> IReadOnlyCollection<'T> to the end of the pipe:



    let inline f<'t> () :IReadOnlyCollection<'t> =
    List.empty
    |> ResizeArray
    |> System.Collections.ObjectModel.ReadOnlyCollection
    |> id<IReadOnlyCollection<_>>


    This works, because now the upcast is inserted automatically when passing the argument to the id function - and this then returns a type that matches with the return type of the function.






    share|improve this answer























    • Yeah auto upcast from ReadOnlyCollection<_> to IReadOnlyList<_> doesn't seem to work
      – Maslow
      Nov 9 at 4:56












    • @Maslow My trivial test (see edit) worked - it would be interesting to see a small counter-example for this - I suspect there is one, because the auto-upcasts are not perfect, but I'm not sure what exactly it needs to look like...
      – Tomas Petricek
      Nov 9 at 14:51










    • edited to add the sample
      – Maslow
      Nov 9 at 16:46










    • dammit, I was in an edit frenzy on the question and edited your answer on accident, and I'm not sure I can undo that
      – Maslow
      Nov 9 at 16:50












    • @Maslow Thanks for the example! This is actually a bit different situation - see my Edit 2!
      – Tomas Petricek
      Nov 10 at 23:43















    up vote
    5
    down vote













    As far as I know, specifying the kind of constraint between 'T and 'TResult is not possible. There is a related question about this with links to more information and a feature request.



    That said, I wonder why do you need this? The F# compiler is able to insert upcasts automatically, even when using pipes, so if you want to do this as part of a longer pipe, it should not be needed. Here is a simple illustration:



    type Animal = interface end
    type Dog = inherit Animal

    let makeDog () = { new Dog }
    let consumeAnimal (a:Animal) = 0

    makeDog () |> consumeAnimal


    I guess you might need pipe-able upcast if you wanted to have it at the end of the pipeline, but then I'd just do the upcast on a separate line. Or is your question motivated by some more complicated cases where the implicit upcast does not work?



    EDIT 1: Here is a minimal example using ReadOnlyCollection and IReadOnlyList which works:



    let foo () : System.Collections.ObjectModel.ReadOnlyCollection<int> = failwith "!"
    let bar (x:System.Collections.Generic.IReadOnlyList<int>) = 0

    foo() |> bar


    EDIT 2: To comment on the update - the problem here is that automatic upcasts are only inserted when passing arguments to functions, but in the second example, the type mismatch is between the result of the pipe and the return type of the function. You can get that to work by adding an identity function of type IReadOnlyCollection<'T> -> IReadOnlyCollection<'T> to the end of the pipe:



    let inline f<'t> () :IReadOnlyCollection<'t> =
    List.empty
    |> ResizeArray
    |> System.Collections.ObjectModel.ReadOnlyCollection
    |> id<IReadOnlyCollection<_>>


    This works, because now the upcast is inserted automatically when passing the argument to the id function - and this then returns a type that matches with the return type of the function.






    share|improve this answer























    • Yeah auto upcast from ReadOnlyCollection<_> to IReadOnlyList<_> doesn't seem to work
      – Maslow
      Nov 9 at 4:56












    • @Maslow My trivial test (see edit) worked - it would be interesting to see a small counter-example for this - I suspect there is one, because the auto-upcasts are not perfect, but I'm not sure what exactly it needs to look like...
      – Tomas Petricek
      Nov 9 at 14:51










    • edited to add the sample
      – Maslow
      Nov 9 at 16:46










    • dammit, I was in an edit frenzy on the question and edited your answer on accident, and I'm not sure I can undo that
      – Maslow
      Nov 9 at 16:50












    • @Maslow Thanks for the example! This is actually a bit different situation - see my Edit 2!
      – Tomas Petricek
      Nov 10 at 23:43













    up vote
    5
    down vote










    up vote
    5
    down vote









    As far as I know, specifying the kind of constraint between 'T and 'TResult is not possible. There is a related question about this with links to more information and a feature request.



    That said, I wonder why do you need this? The F# compiler is able to insert upcasts automatically, even when using pipes, so if you want to do this as part of a longer pipe, it should not be needed. Here is a simple illustration:



    type Animal = interface end
    type Dog = inherit Animal

    let makeDog () = { new Dog }
    let consumeAnimal (a:Animal) = 0

    makeDog () |> consumeAnimal


    I guess you might need pipe-able upcast if you wanted to have it at the end of the pipeline, but then I'd just do the upcast on a separate line. Or is your question motivated by some more complicated cases where the implicit upcast does not work?



    EDIT 1: Here is a minimal example using ReadOnlyCollection and IReadOnlyList which works:



    let foo () : System.Collections.ObjectModel.ReadOnlyCollection<int> = failwith "!"
    let bar (x:System.Collections.Generic.IReadOnlyList<int>) = 0

    foo() |> bar


    EDIT 2: To comment on the update - the problem here is that automatic upcasts are only inserted when passing arguments to functions, but in the second example, the type mismatch is between the result of the pipe and the return type of the function. You can get that to work by adding an identity function of type IReadOnlyCollection<'T> -> IReadOnlyCollection<'T> to the end of the pipe:



    let inline f<'t> () :IReadOnlyCollection<'t> =
    List.empty
    |> ResizeArray
    |> System.Collections.ObjectModel.ReadOnlyCollection
    |> id<IReadOnlyCollection<_>>


    This works, because now the upcast is inserted automatically when passing the argument to the id function - and this then returns a type that matches with the return type of the function.






    share|improve this answer














    As far as I know, specifying the kind of constraint between 'T and 'TResult is not possible. There is a related question about this with links to more information and a feature request.



    That said, I wonder why do you need this? The F# compiler is able to insert upcasts automatically, even when using pipes, so if you want to do this as part of a longer pipe, it should not be needed. Here is a simple illustration:



    type Animal = interface end
    type Dog = inherit Animal

    let makeDog () = { new Dog }
    let consumeAnimal (a:Animal) = 0

    makeDog () |> consumeAnimal


    I guess you might need pipe-able upcast if you wanted to have it at the end of the pipeline, but then I'd just do the upcast on a separate line. Or is your question motivated by some more complicated cases where the implicit upcast does not work?



    EDIT 1: Here is a minimal example using ReadOnlyCollection and IReadOnlyList which works:



    let foo () : System.Collections.ObjectModel.ReadOnlyCollection<int> = failwith "!"
    let bar (x:System.Collections.Generic.IReadOnlyList<int>) = 0

    foo() |> bar


    EDIT 2: To comment on the update - the problem here is that automatic upcasts are only inserted when passing arguments to functions, but in the second example, the type mismatch is between the result of the pipe and the return type of the function. You can get that to work by adding an identity function of type IReadOnlyCollection<'T> -> IReadOnlyCollection<'T> to the end of the pipe:



    let inline f<'t> () :IReadOnlyCollection<'t> =
    List.empty
    |> ResizeArray
    |> System.Collections.ObjectModel.ReadOnlyCollection
    |> id<IReadOnlyCollection<_>>


    This works, because now the upcast is inserted automatically when passing the argument to the id function - and this then returns a type that matches with the return type of the function.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 10 at 23:43

























    answered Nov 8 at 21:28









    Tomas Petricek

    196k13285458




    196k13285458












    • Yeah auto upcast from ReadOnlyCollection<_> to IReadOnlyList<_> doesn't seem to work
      – Maslow
      Nov 9 at 4:56












    • @Maslow My trivial test (see edit) worked - it would be interesting to see a small counter-example for this - I suspect there is one, because the auto-upcasts are not perfect, but I'm not sure what exactly it needs to look like...
      – Tomas Petricek
      Nov 9 at 14:51










    • edited to add the sample
      – Maslow
      Nov 9 at 16:46










    • dammit, I was in an edit frenzy on the question and edited your answer on accident, and I'm not sure I can undo that
      – Maslow
      Nov 9 at 16:50












    • @Maslow Thanks for the example! This is actually a bit different situation - see my Edit 2!
      – Tomas Petricek
      Nov 10 at 23:43


















    • Yeah auto upcast from ReadOnlyCollection<_> to IReadOnlyList<_> doesn't seem to work
      – Maslow
      Nov 9 at 4:56












    • @Maslow My trivial test (see edit) worked - it would be interesting to see a small counter-example for this - I suspect there is one, because the auto-upcasts are not perfect, but I'm not sure what exactly it needs to look like...
      – Tomas Petricek
      Nov 9 at 14:51










    • edited to add the sample
      – Maslow
      Nov 9 at 16:46










    • dammit, I was in an edit frenzy on the question and edited your answer on accident, and I'm not sure I can undo that
      – Maslow
      Nov 9 at 16:50












    • @Maslow Thanks for the example! This is actually a bit different situation - see my Edit 2!
      – Tomas Petricek
      Nov 10 at 23:43
















    Yeah auto upcast from ReadOnlyCollection<_> to IReadOnlyList<_> doesn't seem to work
    – Maslow
    Nov 9 at 4:56






    Yeah auto upcast from ReadOnlyCollection<_> to IReadOnlyList<_> doesn't seem to work
    – Maslow
    Nov 9 at 4:56














    @Maslow My trivial test (see edit) worked - it would be interesting to see a small counter-example for this - I suspect there is one, because the auto-upcasts are not perfect, but I'm not sure what exactly it needs to look like...
    – Tomas Petricek
    Nov 9 at 14:51




    @Maslow My trivial test (see edit) worked - it would be interesting to see a small counter-example for this - I suspect there is one, because the auto-upcasts are not perfect, but I'm not sure what exactly it needs to look like...
    – Tomas Petricek
    Nov 9 at 14:51












    edited to add the sample
    – Maslow
    Nov 9 at 16:46




    edited to add the sample
    – Maslow
    Nov 9 at 16:46












    dammit, I was in an edit frenzy on the question and edited your answer on accident, and I'm not sure I can undo that
    – Maslow
    Nov 9 at 16:50






    dammit, I was in an edit frenzy on the question and edited your answer on accident, and I'm not sure I can undo that
    – Maslow
    Nov 9 at 16:50














    @Maslow Thanks for the example! This is actually a bit different situation - see my Edit 2!
    – Tomas Petricek
    Nov 10 at 23:43




    @Maslow Thanks for the example! This is actually a bit different situation - see my Edit 2!
    – Tomas Petricek
    Nov 10 at 23:43












    up vote
    0
    down vote













    much simpler and unexpected



    let inline f2<'t>() : IReadOnlyCollection<'t> = 
    List.empty
    |> ResizeArray
    |> System.Collections.ObjectModel.ReadOnlyCollection
    :> _





    share|improve this answer

























      up vote
      0
      down vote













      much simpler and unexpected



      let inline f2<'t>() : IReadOnlyCollection<'t> = 
      List.empty
      |> ResizeArray
      |> System.Collections.ObjectModel.ReadOnlyCollection
      :> _





      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        much simpler and unexpected



        let inline f2<'t>() : IReadOnlyCollection<'t> = 
        List.empty
        |> ResizeArray
        |> System.Collections.ObjectModel.ReadOnlyCollection
        :> _





        share|improve this answer












        much simpler and unexpected



        let inline f2<'t>() : IReadOnlyCollection<'t> = 
        List.empty
        |> ResizeArray
        |> System.Collections.ObjectModel.ReadOnlyCollection
        :> _






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 12 at 1:12









        Maslow

        12.5k1482167




        12.5k1482167






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53214150%2fis-there-already-or-can-i-declare-a-more-pipe-friendly-upcast%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Xamarin.iOS Cant Deploy on Iphone

            Glorious Revolution

            Dulmage-Mendelsohn matrix decomposition in Python