Avoid specifying guard clause when using struct
I have a struct:
defmodule Company do
defstruct [:id, :name, :active]
end
I have a function that requires one of its arguments to be of this struct:
def create(connection, %Company{id: id} = company) do
# stuff
end
Is there any way I can enforce type-checking without using a guard clause? Right now I have to do this:
def create(connection, %Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active) do
# stuff
end
Edit: this question in specific is regarding arguments in a function definition that use a struct
.
elixir
add a comment |
I have a struct:
defmodule Company do
defstruct [:id, :name, :active]
end
I have a function that requires one of its arguments to be of this struct:
def create(connection, %Company{id: id} = company) do
# stuff
end
Is there any way I can enforce type-checking without using a guard clause? Right now I have to do this:
def create(connection, %Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active) do
# stuff
end
Edit: this question in specific is regarding arguments in a function definition that use a struct
.
elixir
Possible duplicate of How can types and values be validated / enforced for Elixir structs?
– Gabriel Prá
Nov 25 '18 at 15:23
add a comment |
I have a struct:
defmodule Company do
defstruct [:id, :name, :active]
end
I have a function that requires one of its arguments to be of this struct:
def create(connection, %Company{id: id} = company) do
# stuff
end
Is there any way I can enforce type-checking without using a guard clause? Right now I have to do this:
def create(connection, %Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active) do
# stuff
end
Edit: this question in specific is regarding arguments in a function definition that use a struct
.
elixir
I have a struct:
defmodule Company do
defstruct [:id, :name, :active]
end
I have a function that requires one of its arguments to be of this struct:
def create(connection, %Company{id: id} = company) do
# stuff
end
Is there any way I can enforce type-checking without using a guard clause? Right now I have to do this:
def create(connection, %Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active) do
# stuff
end
Edit: this question in specific is regarding arguments in a function definition that use a struct
.
elixir
elixir
edited Nov 25 '18 at 19:42
dimiguel
asked Nov 25 '18 at 9:48
dimigueldimiguel
730824
730824
Possible duplicate of How can types and values be validated / enforced for Elixir structs?
– Gabriel Prá
Nov 25 '18 at 15:23
add a comment |
Possible duplicate of How can types and values be validated / enforced for Elixir structs?
– Gabriel Prá
Nov 25 '18 at 15:23
Possible duplicate of How can types and values be validated / enforced for Elixir structs?
– Gabriel Prá
Nov 25 '18 at 15:23
Possible duplicate of How can types and values be validated / enforced for Elixir structs?
– Gabriel Prá
Nov 25 '18 at 15:23
add a comment |
3 Answers
3
active
oldest
votes
No, there is no way to enforce type check without guards. Erlang (and hence Elixir) is a dynamically typed language and you might want to have different clauses for different types passed, e.g. an error message if the types do not conform, or just sink the input out, or whatever.
def create(connection, %Company{id: id})
when not is_integer(id) do
raise "Must be integer"
end
Erlang does not take out the liberty to deal with not proper input in the way you need, that is why guards you use is the way to go.
There is static analysis tool, dialyzer
, you might use to statically check types, also it does not prevent the compiler and runtime to pass whatever type is passed.
add a comment |
As @Aleksei has already pointed out, type-checking is not enforced in Elixir since it's a dynamically-typed language, so to do it manually we usually do it in a guard clause.
But repeating the same set of clauses over and over again can be messy, tiring and error-prone. Though you could "validate" them in a separate function and make it easier, but it won't be as performant as guards:
defmodule Company do
defstruct [:id, :name, :active]
def create(connection, company) do
with :ok <- validate(company) do
# do something
end
end
defp validate(%Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active),
do: :ok
defp validate(_term), do: raise "Invalid Company"
end
Now calling the function for Company
would work as expected, while it would raise errors for other terms:
Company.create(1, %Company{})
# => ** (RuntimeError) Invalid Company
Company.create(2, %Company{id: 1, name: "hello", active: false})
# => ... (works normally)
If your use-case was simpler, you could've retained the performance by defining a custom guard-clause.
add a comment |
I think its more idiomatic in Elixir to consider the contents of a struct to be valid data. And to provide a factory function to create a struct as part of your public API as @Sheharyar suggests above. I typically see the function be called new
not create
but thats preference more than dogma.
As long as your code adheres to using the <module>.new
function to create structs you don't need to add repetitive guards on every function. If it all goes wrong, let it crash.
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%2f53466332%2favoid-specifying-guard-clause-when-using-struct%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
No, there is no way to enforce type check without guards. Erlang (and hence Elixir) is a dynamically typed language and you might want to have different clauses for different types passed, e.g. an error message if the types do not conform, or just sink the input out, or whatever.
def create(connection, %Company{id: id})
when not is_integer(id) do
raise "Must be integer"
end
Erlang does not take out the liberty to deal with not proper input in the way you need, that is why guards you use is the way to go.
There is static analysis tool, dialyzer
, you might use to statically check types, also it does not prevent the compiler and runtime to pass whatever type is passed.
add a comment |
No, there is no way to enforce type check without guards. Erlang (and hence Elixir) is a dynamically typed language and you might want to have different clauses for different types passed, e.g. an error message if the types do not conform, or just sink the input out, or whatever.
def create(connection, %Company{id: id})
when not is_integer(id) do
raise "Must be integer"
end
Erlang does not take out the liberty to deal with not proper input in the way you need, that is why guards you use is the way to go.
There is static analysis tool, dialyzer
, you might use to statically check types, also it does not prevent the compiler and runtime to pass whatever type is passed.
add a comment |
No, there is no way to enforce type check without guards. Erlang (and hence Elixir) is a dynamically typed language and you might want to have different clauses for different types passed, e.g. an error message if the types do not conform, or just sink the input out, or whatever.
def create(connection, %Company{id: id})
when not is_integer(id) do
raise "Must be integer"
end
Erlang does not take out the liberty to deal with not proper input in the way you need, that is why guards you use is the way to go.
There is static analysis tool, dialyzer
, you might use to statically check types, also it does not prevent the compiler and runtime to pass whatever type is passed.
No, there is no way to enforce type check without guards. Erlang (and hence Elixir) is a dynamically typed language and you might want to have different clauses for different types passed, e.g. an error message if the types do not conform, or just sink the input out, or whatever.
def create(connection, %Company{id: id})
when not is_integer(id) do
raise "Must be integer"
end
Erlang does not take out the liberty to deal with not proper input in the way you need, that is why guards you use is the way to go.
There is static analysis tool, dialyzer
, you might use to statically check types, also it does not prevent the compiler and runtime to pass whatever type is passed.
answered Nov 25 '18 at 15:15
Aleksei MatiushkinAleksei Matiushkin
83.2k95694
83.2k95694
add a comment |
add a comment |
As @Aleksei has already pointed out, type-checking is not enforced in Elixir since it's a dynamically-typed language, so to do it manually we usually do it in a guard clause.
But repeating the same set of clauses over and over again can be messy, tiring and error-prone. Though you could "validate" them in a separate function and make it easier, but it won't be as performant as guards:
defmodule Company do
defstruct [:id, :name, :active]
def create(connection, company) do
with :ok <- validate(company) do
# do something
end
end
defp validate(%Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active),
do: :ok
defp validate(_term), do: raise "Invalid Company"
end
Now calling the function for Company
would work as expected, while it would raise errors for other terms:
Company.create(1, %Company{})
# => ** (RuntimeError) Invalid Company
Company.create(2, %Company{id: 1, name: "hello", active: false})
# => ... (works normally)
If your use-case was simpler, you could've retained the performance by defining a custom guard-clause.
add a comment |
As @Aleksei has already pointed out, type-checking is not enforced in Elixir since it's a dynamically-typed language, so to do it manually we usually do it in a guard clause.
But repeating the same set of clauses over and over again can be messy, tiring and error-prone. Though you could "validate" them in a separate function and make it easier, but it won't be as performant as guards:
defmodule Company do
defstruct [:id, :name, :active]
def create(connection, company) do
with :ok <- validate(company) do
# do something
end
end
defp validate(%Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active),
do: :ok
defp validate(_term), do: raise "Invalid Company"
end
Now calling the function for Company
would work as expected, while it would raise errors for other terms:
Company.create(1, %Company{})
# => ** (RuntimeError) Invalid Company
Company.create(2, %Company{id: 1, name: "hello", active: false})
# => ... (works normally)
If your use-case was simpler, you could've retained the performance by defining a custom guard-clause.
add a comment |
As @Aleksei has already pointed out, type-checking is not enforced in Elixir since it's a dynamically-typed language, so to do it manually we usually do it in a guard clause.
But repeating the same set of clauses over and over again can be messy, tiring and error-prone. Though you could "validate" them in a separate function and make it easier, but it won't be as performant as guards:
defmodule Company do
defstruct [:id, :name, :active]
def create(connection, company) do
with :ok <- validate(company) do
# do something
end
end
defp validate(%Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active),
do: :ok
defp validate(_term), do: raise "Invalid Company"
end
Now calling the function for Company
would work as expected, while it would raise errors for other terms:
Company.create(1, %Company{})
# => ** (RuntimeError) Invalid Company
Company.create(2, %Company{id: 1, name: "hello", active: false})
# => ... (works normally)
If your use-case was simpler, you could've retained the performance by defining a custom guard-clause.
As @Aleksei has already pointed out, type-checking is not enforced in Elixir since it's a dynamically-typed language, so to do it manually we usually do it in a guard clause.
But repeating the same set of clauses over and over again can be messy, tiring and error-prone. Though you could "validate" them in a separate function and make it easier, but it won't be as performant as guards:
defmodule Company do
defstruct [:id, :name, :active]
def create(connection, company) do
with :ok <- validate(company) do
# do something
end
end
defp validate(%Company{id: id, name: name, active: active})
when is_integer(id) and is_binary(name) and is_boolean(active),
do: :ok
defp validate(_term), do: raise "Invalid Company"
end
Now calling the function for Company
would work as expected, while it would raise errors for other terms:
Company.create(1, %Company{})
# => ** (RuntimeError) Invalid Company
Company.create(2, %Company{id: 1, name: "hello", active: false})
# => ... (works normally)
If your use-case was simpler, you could've retained the performance by defining a custom guard-clause.
edited Nov 26 '18 at 1:02
answered Nov 25 '18 at 22:40
SheharyarSheharyar
45.9k12109162
45.9k12109162
add a comment |
add a comment |
I think its more idiomatic in Elixir to consider the contents of a struct to be valid data. And to provide a factory function to create a struct as part of your public API as @Sheharyar suggests above. I typically see the function be called new
not create
but thats preference more than dogma.
As long as your code adheres to using the <module>.new
function to create structs you don't need to add repetitive guards on every function. If it all goes wrong, let it crash.
add a comment |
I think its more idiomatic in Elixir to consider the contents of a struct to be valid data. And to provide a factory function to create a struct as part of your public API as @Sheharyar suggests above. I typically see the function be called new
not create
but thats preference more than dogma.
As long as your code adheres to using the <module>.new
function to create structs you don't need to add repetitive guards on every function. If it all goes wrong, let it crash.
add a comment |
I think its more idiomatic in Elixir to consider the contents of a struct to be valid data. And to provide a factory function to create a struct as part of your public API as @Sheharyar suggests above. I typically see the function be called new
not create
but thats preference more than dogma.
As long as your code adheres to using the <module>.new
function to create structs you don't need to add repetitive guards on every function. If it all goes wrong, let it crash.
I think its more idiomatic in Elixir to consider the contents of a struct to be valid data. And to provide a factory function to create a struct as part of your public API as @Sheharyar suggests above. I typically see the function be called new
not create
but thats preference more than dogma.
As long as your code adheres to using the <module>.new
function to create structs you don't need to add repetitive guards on every function. If it all goes wrong, let it crash.
answered Nov 26 '18 at 9:19
KipKip
37927
37927
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%2f53466332%2favoid-specifying-guard-clause-when-using-struct%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
Possible duplicate of How can types and values be validated / enforced for Elixir structs?
– Gabriel Prá
Nov 25 '18 at 15:23