static members vs module for type in F#?
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#
add a comment |
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#
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
add a comment |
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#
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#
f#
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
add a comment |
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
add a comment |
2 Answers
2
active
oldest
votes
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.
add a comment |
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
add a comment |
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.
add a comment |
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.
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.
answered Dec 30 '18 at 22:26
scrwtpscrwtp
11.4k11626
11.4k11626
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Dec 30 '18 at 22:21
Jim FoyeJim Foye
22836
22836
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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