static members vs module for type in F#?












11















Suppose I have a type like this:



type Season =
| Spring
| Summer
| Autumn
| Winter


I want to have a function next that returns the next season:



let next s = 
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


There are two places I can put this function.



In a named module:



module Season = 
let next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


Or as a static member on the type:



type Season =
| Spring
| Summer
| Autumn
| Winter
with
static member next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


What are the reasons to favour each approach?










share|improve this question


















  • 1





    An enum might work better for this specific case. What if you need the previous season? Module is really just a name spacing construct in F#, and it works for library functions well (e.g. List, which is auto-opened), but otherwise I would avoid it. That said it can be nice for domain modelling, and you might have a lot of functions operating on Season, other languages solve it by being able to define methods on the type outside the type, but module might work for you. Too bad you can't accept two answers. :D

    – s952163
    Jan 2 at 0:19
















11















Suppose I have a type like this:



type Season =
| Spring
| Summer
| Autumn
| Winter


I want to have a function next that returns the next season:



let next s = 
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


There are two places I can put this function.



In a named module:



module Season = 
let next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


Or as a static member on the type:



type Season =
| Spring
| Summer
| Autumn
| Winter
with
static member next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


What are the reasons to favour each approach?










share|improve this question


















  • 1





    An enum might work better for this specific case. What if you need the previous season? Module is really just a name spacing construct in F#, and it works for library functions well (e.g. List, which is auto-opened), but otherwise I would avoid it. That said it can be nice for domain modelling, and you might have a lot of functions operating on Season, other languages solve it by being able to define methods on the type outside the type, but module might work for you. Too bad you can't accept two answers. :D

    – s952163
    Jan 2 at 0:19














11












11








11


2






Suppose I have a type like this:



type Season =
| Spring
| Summer
| Autumn
| Winter


I want to have a function next that returns the next season:



let next s = 
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


There are two places I can put this function.



In a named module:



module Season = 
let next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


Or as a static member on the type:



type Season =
| Spring
| Summer
| Autumn
| Winter
with
static member next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


What are the reasons to favour each approach?










share|improve this question














Suppose I have a type like this:



type Season =
| Spring
| Summer
| Autumn
| Winter


I want to have a function next that returns the next season:



let next s = 
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


There are two places I can put this function.



In a named module:



module Season = 
let next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


Or as a static member on the type:



type Season =
| Spring
| Summer
| Autumn
| Winter
with
static member next s =
match s with
| Spring -> Summer
| Summer -> Autumn
| Autumn -> Winter
| Winter -> Spring


What are the reasons to favour each approach?







f#






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 30 '18 at 16:39









sdgfsdhsdgfsdh

8,20383995




8,20383995








  • 1





    An enum might work better for this specific case. What if you need the previous season? Module is really just a name spacing construct in F#, and it works for library functions well (e.g. List, which is auto-opened), but otherwise I would avoid it. That said it can be nice for domain modelling, and you might have a lot of functions operating on Season, other languages solve it by being able to define methods on the type outside the type, but module might work for you. Too bad you can't accept two answers. :D

    – s952163
    Jan 2 at 0:19














  • 1





    An enum might work better for this specific case. What if you need the previous season? Module is really just a name spacing construct in F#, and it works for library functions well (e.g. List, which is auto-opened), but otherwise I would avoid it. That said it can be nice for domain modelling, and you might have a lot of functions operating on Season, other languages solve it by being able to define methods on the type outside the type, but module might work for you. Too bad you can't accept two answers. :D

    – s952163
    Jan 2 at 0:19








1




1





An enum might work better for this specific case. What if you need the previous season? Module is really just a name spacing construct in F#, and it works for library functions well (e.g. List, which is auto-opened), but otherwise I would avoid it. That said it can be nice for domain modelling, and you might have a lot of functions operating on Season, other languages solve it by being able to define methods on the type outside the type, but module might work for you. Too bad you can't accept two answers. :D

– s952163
Jan 2 at 0:19





An enum might work better for this specific case. What if you need the previous season? Module is really just a name spacing construct in F#, and it works for library functions well (e.g. List, which is auto-opened), but otherwise I would avoid it. That said it can be nice for domain modelling, and you might have a lot of functions operating on Season, other languages solve it by being able to define methods on the type outside the type, but module might work for you. Too bad you can't accept two answers. :D

– s952163
Jan 2 at 0:19












2 Answers
2






active

oldest

votes


















3














Ultimately that's a domain modelling judgement call and there's no one definite correct answer here. What matters is how each choice affects readability and maintainability of the code.



I tend to favor static members for functionality that is highly "cohesive" with the type, more so than any particular piece of business logic code. Think Parse functions or smart constructors/factory methods. The general approach being that if I were to refactor the code by moving the type somewhere else, those would be the functions I'd definitely want to move together with it. Having them as static members also helps discoverability through intellisense, as you only need to know the name of the type to find them.



On the other hand, I'd use a module to house business logic that represents some abstract process, and if the function in question is somehow specific to that business logic and unlikely to be useful outside of it, then I'd go with a function in a module even if it's still somewhat type specific. For instance, a very purpose-specific parser that's only useful as part of this one workflow for legacy reasons would be a let-bound function rather than a static member, because other clients that use that type generally shouldn't even know about that function.



In your case, I'd go with the static member Next if it makes sense for it to be used in multiple different modules in your context - if being able to cycle through Seasons is a fundamental quality that defines what a Season is.



Otherwise if you just have a single module, let's say WeatherPatterns, that adjusts rainfall based on season changes, and that's the only part of your code where you care about cycling through Seasons, then I'd put it as a function in that module.






share|improve this answer































    2














    Your example is pretty simple, and so either approach here is probably fine. But imagine adding a dozen more functions that take a Season parameter. Now the type definition will look extremely cluttered. Plus, these functions may need to make use of some shared values and functions that can be declared as private inside the Season module.






    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',
      autoActivateHeartbeat: false,
      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%2f53979464%2fstatic-members-vs-module-for-type-in-f%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









      3














      Ultimately that's a domain modelling judgement call and there's no one definite correct answer here. What matters is how each choice affects readability and maintainability of the code.



      I tend to favor static members for functionality that is highly "cohesive" with the type, more so than any particular piece of business logic code. Think Parse functions or smart constructors/factory methods. The general approach being that if I were to refactor the code by moving the type somewhere else, those would be the functions I'd definitely want to move together with it. Having them as static members also helps discoverability through intellisense, as you only need to know the name of the type to find them.



      On the other hand, I'd use a module to house business logic that represents some abstract process, and if the function in question is somehow specific to that business logic and unlikely to be useful outside of it, then I'd go with a function in a module even if it's still somewhat type specific. For instance, a very purpose-specific parser that's only useful as part of this one workflow for legacy reasons would be a let-bound function rather than a static member, because other clients that use that type generally shouldn't even know about that function.



      In your case, I'd go with the static member Next if it makes sense for it to be used in multiple different modules in your context - if being able to cycle through Seasons is a fundamental quality that defines what a Season is.



      Otherwise if you just have a single module, let's say WeatherPatterns, that adjusts rainfall based on season changes, and that's the only part of your code where you care about cycling through Seasons, then I'd put it as a function in that module.






      share|improve this answer




























        3














        Ultimately that's a domain modelling judgement call and there's no one definite correct answer here. What matters is how each choice affects readability and maintainability of the code.



        I tend to favor static members for functionality that is highly "cohesive" with the type, more so than any particular piece of business logic code. Think Parse functions or smart constructors/factory methods. The general approach being that if I were to refactor the code by moving the type somewhere else, those would be the functions I'd definitely want to move together with it. Having them as static members also helps discoverability through intellisense, as you only need to know the name of the type to find them.



        On the other hand, I'd use a module to house business logic that represents some abstract process, and if the function in question is somehow specific to that business logic and unlikely to be useful outside of it, then I'd go with a function in a module even if it's still somewhat type specific. For instance, a very purpose-specific parser that's only useful as part of this one workflow for legacy reasons would be a let-bound function rather than a static member, because other clients that use that type generally shouldn't even know about that function.



        In your case, I'd go with the static member Next if it makes sense for it to be used in multiple different modules in your context - if being able to cycle through Seasons is a fundamental quality that defines what a Season is.



        Otherwise if you just have a single module, let's say WeatherPatterns, that adjusts rainfall based on season changes, and that's the only part of your code where you care about cycling through Seasons, then I'd put it as a function in that module.






        share|improve this answer


























          3












          3








          3







          Ultimately that's a domain modelling judgement call and there's no one definite correct answer here. What matters is how each choice affects readability and maintainability of the code.



          I tend to favor static members for functionality that is highly "cohesive" with the type, more so than any particular piece of business logic code. Think Parse functions or smart constructors/factory methods. The general approach being that if I were to refactor the code by moving the type somewhere else, those would be the functions I'd definitely want to move together with it. Having them as static members also helps discoverability through intellisense, as you only need to know the name of the type to find them.



          On the other hand, I'd use a module to house business logic that represents some abstract process, and if the function in question is somehow specific to that business logic and unlikely to be useful outside of it, then I'd go with a function in a module even if it's still somewhat type specific. For instance, a very purpose-specific parser that's only useful as part of this one workflow for legacy reasons would be a let-bound function rather than a static member, because other clients that use that type generally shouldn't even know about that function.



          In your case, I'd go with the static member Next if it makes sense for it to be used in multiple different modules in your context - if being able to cycle through Seasons is a fundamental quality that defines what a Season is.



          Otherwise if you just have a single module, let's say WeatherPatterns, that adjusts rainfall based on season changes, and that's the only part of your code where you care about cycling through Seasons, then I'd put it as a function in that module.






          share|improve this answer













          Ultimately that's a domain modelling judgement call and there's no one definite correct answer here. What matters is how each choice affects readability and maintainability of the code.



          I tend to favor static members for functionality that is highly "cohesive" with the type, more so than any particular piece of business logic code. Think Parse functions or smart constructors/factory methods. The general approach being that if I were to refactor the code by moving the type somewhere else, those would be the functions I'd definitely want to move together with it. Having them as static members also helps discoverability through intellisense, as you only need to know the name of the type to find them.



          On the other hand, I'd use a module to house business logic that represents some abstract process, and if the function in question is somehow specific to that business logic and unlikely to be useful outside of it, then I'd go with a function in a module even if it's still somewhat type specific. For instance, a very purpose-specific parser that's only useful as part of this one workflow for legacy reasons would be a let-bound function rather than a static member, because other clients that use that type generally shouldn't even know about that function.



          In your case, I'd go with the static member Next if it makes sense for it to be used in multiple different modules in your context - if being able to cycle through Seasons is a fundamental quality that defines what a Season is.



          Otherwise if you just have a single module, let's say WeatherPatterns, that adjusts rainfall based on season changes, and that's the only part of your code where you care about cycling through Seasons, then I'd put it as a function in that module.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 30 '18 at 22:26









          scrwtpscrwtp

          11.4k11626




          11.4k11626

























              2














              Your example is pretty simple, and so either approach here is probably fine. But imagine adding a dozen more functions that take a Season parameter. Now the type definition will look extremely cluttered. Plus, these functions may need to make use of some shared values and functions that can be declared as private inside the Season module.






              share|improve this answer




























                2














                Your example is pretty simple, and so either approach here is probably fine. But imagine adding a dozen more functions that take a Season parameter. Now the type definition will look extremely cluttered. Plus, these functions may need to make use of some shared values and functions that can be declared as private inside the Season module.






                share|improve this answer


























                  2












                  2








                  2







                  Your example is pretty simple, and so either approach here is probably fine. But imagine adding a dozen more functions that take a Season parameter. Now the type definition will look extremely cluttered. Plus, these functions may need to make use of some shared values and functions that can be declared as private inside the Season module.






                  share|improve this answer













                  Your example is pretty simple, and so either approach here is probably fine. But imagine adding a dozen more functions that take a Season parameter. Now the type definition will look extremely cluttered. Plus, these functions may need to make use of some shared values and functions that can be declared as private inside the Season module.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 30 '18 at 22:21









                  Jim FoyeJim Foye

                  22836




                  22836






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53979464%2fstatic-members-vs-module-for-type-in-f%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

                      Mossoró

                      Error while reading .h5 file using the rhdf5 package in R

                      Pushsharp Apns notification error: 'InvalidToken'