how and why is defmulti and defmethod used? and what are the advantages?
I would like to know why defmulti & defmethod are used?
What are the advantages?
And how do you use it? Please explain what is happening in the code.
clojure
add a comment |
I would like to know why defmulti & defmethod are used?
What are the advantages?
And how do you use it? Please explain what is happening in the code.
clojure
Are you able to define what a multimethod is? If not then I'll be happy to explain you
– tgoossens
Oct 13 '12 at 11:42
Here is a question I once asked: cs.stackexchange.com/questions/4660/… I answered my own question as well, this might help you understand what a multimethod is
– tgoossens
Oct 13 '12 at 11:43
add a comment |
I would like to know why defmulti & defmethod are used?
What are the advantages?
And how do you use it? Please explain what is happening in the code.
clojure
I would like to know why defmulti & defmethod are used?
What are the advantages?
And how do you use it? Please explain what is happening in the code.
clojure
clojure
asked Oct 13 '12 at 11:08
PhilPhil
9263919
9263919
Are you able to define what a multimethod is? If not then I'll be happy to explain you
– tgoossens
Oct 13 '12 at 11:42
Here is a question I once asked: cs.stackexchange.com/questions/4660/… I answered my own question as well, this might help you understand what a multimethod is
– tgoossens
Oct 13 '12 at 11:43
add a comment |
Are you able to define what a multimethod is? If not then I'll be happy to explain you
– tgoossens
Oct 13 '12 at 11:42
Here is a question I once asked: cs.stackexchange.com/questions/4660/… I answered my own question as well, this might help you understand what a multimethod is
– tgoossens
Oct 13 '12 at 11:43
Are you able to define what a multimethod is? If not then I'll be happy to explain you
– tgoossens
Oct 13 '12 at 11:42
Are you able to define what a multimethod is? If not then I'll be happy to explain you
– tgoossens
Oct 13 '12 at 11:42
Here is a question I once asked: cs.stackexchange.com/questions/4660/… I answered my own question as well, this might help you understand what a multimethod is
– tgoossens
Oct 13 '12 at 11:43
Here is a question I once asked: cs.stackexchange.com/questions/4660/… I answered my own question as well, this might help you understand what a multimethod is
– tgoossens
Oct 13 '12 at 11:43
add a comment |
3 Answers
3
active
oldest
votes
In "general terms" you would call it a if/else on steroids and in "impress me" style you would name it with "dynamic dispatch", "runtime polymorphism" etc.
Lets say you want to define a function "Add" which should work for various data types like in case of Int it should add the numbers, in case of strings it should concat the strings. Now it is very simple to implement it using if else, basically you check the type of arguments and if they are integers then add them, if they are strings then concat them else throw exception. But the problem with this is that in case you want to add support for new data type in your Add function you will need to modify the Add function, which may not be possible in cases where you don't control the source of Add such as the case it is defined in some library etc.defmulti and defmethod allows you to solve this problem i.e adding a new case to existing function without modifying its code.
(defmulti add (fn [a b] [(type a) (type b)]))
add is the function name, the anonymous function is your if/else, basically this will be called on your add arguments and the return value of this function will be checked if there is any implementation. Now lets implement it for Integer.
(defmethod add [Integer Integer] ([a b] (+ a b)))
[Integer Integer] is sort switch case on the return value of the anonymous function we defined in defmulti and then the implementation.
Similarly we can do for strings
(defmethod add [String String] ([a b] (str a b)))
Calling it with integers (add (int 1) (int 2))
Calling it with strings(add "hello" "world")
Calling it with something that doesn't match our if/else i.e not implementation yet for a case will result in an exception
3
Thank you very much! This was VERY HELPFUL!
– Phil
Oct 13 '12 at 13:30
Thank you for the explanation!
– goncalvesnelson
Apr 19 '14 at 19:34
add a comment |
From what I've observed after reading the answer (and using the example provided above), the following is also helpful to understand:
when you execute the command:
(add (int 5) (int 2))
What happens is that the 'add defmulti' is executed thus producing a list:
[Integer Integer]
with that produced, it looks for any 'add defmethod' that is identified with above list i.e.:
(add [Integer Integer])
And passes on the arguments that it received.
Another way of defining the multi methods so as to make the passing of arguments clear is:
(defmulti add (fn [a b] [(type a) (type b)]))
(defmethod add [Integer Integer] [a b] (+ a b))
(defmethod add [String String] [a b] (str a b))
Then run the function as:
(add 12 73)
or
(add "thank" "you")
add a comment |
Multimethods helps to call the methods based on params passed. It can call the respective methods based on type of argument/or based on some properties of an argument.
Example 1 Based on type
test=> (defmulti multiply (fn [a b] [(type a) (type b)]))
#'test/multiply
test=> (defmethod multiply [Integer Integer] [a b] (* a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (defmethod multiply [String String] [a b] (str a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (multiply 10 10)
test=> (multiply (int 10) (int 10))
100
test=> (multiply "10" "10")
"1010"
Example 2 Based on property
test=> (defmulti mn (fn[a b] ( < a b ) ))
#'test/mn
test=> (defmethod mn true [a b] (+ a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (defmethod mn false [a b] (- a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (mn 1 2)
3
test=> (mn 2 1)
1
test=> (mn 1 1)
0
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%2f12872513%2fhow-and-why-is-defmulti-and-defmethod-used-and-what-are-the-advantages%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
In "general terms" you would call it a if/else on steroids and in "impress me" style you would name it with "dynamic dispatch", "runtime polymorphism" etc.
Lets say you want to define a function "Add" which should work for various data types like in case of Int it should add the numbers, in case of strings it should concat the strings. Now it is very simple to implement it using if else, basically you check the type of arguments and if they are integers then add them, if they are strings then concat them else throw exception. But the problem with this is that in case you want to add support for new data type in your Add function you will need to modify the Add function, which may not be possible in cases where you don't control the source of Add such as the case it is defined in some library etc.defmulti and defmethod allows you to solve this problem i.e adding a new case to existing function without modifying its code.
(defmulti add (fn [a b] [(type a) (type b)]))
add is the function name, the anonymous function is your if/else, basically this will be called on your add arguments and the return value of this function will be checked if there is any implementation. Now lets implement it for Integer.
(defmethod add [Integer Integer] ([a b] (+ a b)))
[Integer Integer] is sort switch case on the return value of the anonymous function we defined in defmulti and then the implementation.
Similarly we can do for strings
(defmethod add [String String] ([a b] (str a b)))
Calling it with integers (add (int 1) (int 2))
Calling it with strings(add "hello" "world")
Calling it with something that doesn't match our if/else i.e not implementation yet for a case will result in an exception
3
Thank you very much! This was VERY HELPFUL!
– Phil
Oct 13 '12 at 13:30
Thank you for the explanation!
– goncalvesnelson
Apr 19 '14 at 19:34
add a comment |
In "general terms" you would call it a if/else on steroids and in "impress me" style you would name it with "dynamic dispatch", "runtime polymorphism" etc.
Lets say you want to define a function "Add" which should work for various data types like in case of Int it should add the numbers, in case of strings it should concat the strings. Now it is very simple to implement it using if else, basically you check the type of arguments and if they are integers then add them, if they are strings then concat them else throw exception. But the problem with this is that in case you want to add support for new data type in your Add function you will need to modify the Add function, which may not be possible in cases where you don't control the source of Add such as the case it is defined in some library etc.defmulti and defmethod allows you to solve this problem i.e adding a new case to existing function without modifying its code.
(defmulti add (fn [a b] [(type a) (type b)]))
add is the function name, the anonymous function is your if/else, basically this will be called on your add arguments and the return value of this function will be checked if there is any implementation. Now lets implement it for Integer.
(defmethod add [Integer Integer] ([a b] (+ a b)))
[Integer Integer] is sort switch case on the return value of the anonymous function we defined in defmulti and then the implementation.
Similarly we can do for strings
(defmethod add [String String] ([a b] (str a b)))
Calling it with integers (add (int 1) (int 2))
Calling it with strings(add "hello" "world")
Calling it with something that doesn't match our if/else i.e not implementation yet for a case will result in an exception
3
Thank you very much! This was VERY HELPFUL!
– Phil
Oct 13 '12 at 13:30
Thank you for the explanation!
– goncalvesnelson
Apr 19 '14 at 19:34
add a comment |
In "general terms" you would call it a if/else on steroids and in "impress me" style you would name it with "dynamic dispatch", "runtime polymorphism" etc.
Lets say you want to define a function "Add" which should work for various data types like in case of Int it should add the numbers, in case of strings it should concat the strings. Now it is very simple to implement it using if else, basically you check the type of arguments and if they are integers then add them, if they are strings then concat them else throw exception. But the problem with this is that in case you want to add support for new data type in your Add function you will need to modify the Add function, which may not be possible in cases where you don't control the source of Add such as the case it is defined in some library etc.defmulti and defmethod allows you to solve this problem i.e adding a new case to existing function without modifying its code.
(defmulti add (fn [a b] [(type a) (type b)]))
add is the function name, the anonymous function is your if/else, basically this will be called on your add arguments and the return value of this function will be checked if there is any implementation. Now lets implement it for Integer.
(defmethod add [Integer Integer] ([a b] (+ a b)))
[Integer Integer] is sort switch case on the return value of the anonymous function we defined in defmulti and then the implementation.
Similarly we can do for strings
(defmethod add [String String] ([a b] (str a b)))
Calling it with integers (add (int 1) (int 2))
Calling it with strings(add "hello" "world")
Calling it with something that doesn't match our if/else i.e not implementation yet for a case will result in an exception
In "general terms" you would call it a if/else on steroids and in "impress me" style you would name it with "dynamic dispatch", "runtime polymorphism" etc.
Lets say you want to define a function "Add" which should work for various data types like in case of Int it should add the numbers, in case of strings it should concat the strings. Now it is very simple to implement it using if else, basically you check the type of arguments and if they are integers then add them, if they are strings then concat them else throw exception. But the problem with this is that in case you want to add support for new data type in your Add function you will need to modify the Add function, which may not be possible in cases where you don't control the source of Add such as the case it is defined in some library etc.defmulti and defmethod allows you to solve this problem i.e adding a new case to existing function without modifying its code.
(defmulti add (fn [a b] [(type a) (type b)]))
add is the function name, the anonymous function is your if/else, basically this will be called on your add arguments and the return value of this function will be checked if there is any implementation. Now lets implement it for Integer.
(defmethod add [Integer Integer] ([a b] (+ a b)))
[Integer Integer] is sort switch case on the return value of the anonymous function we defined in defmulti and then the implementation.
Similarly we can do for strings
(defmethod add [String String] ([a b] (str a b)))
Calling it with integers (add (int 1) (int 2))
Calling it with strings(add "hello" "world")
Calling it with something that doesn't match our if/else i.e not implementation yet for a case will result in an exception
answered Oct 13 '12 at 12:06
AnkurAnkur
30.2k23260
30.2k23260
3
Thank you very much! This was VERY HELPFUL!
– Phil
Oct 13 '12 at 13:30
Thank you for the explanation!
– goncalvesnelson
Apr 19 '14 at 19:34
add a comment |
3
Thank you very much! This was VERY HELPFUL!
– Phil
Oct 13 '12 at 13:30
Thank you for the explanation!
– goncalvesnelson
Apr 19 '14 at 19:34
3
3
Thank you very much! This was VERY HELPFUL!
– Phil
Oct 13 '12 at 13:30
Thank you very much! This was VERY HELPFUL!
– Phil
Oct 13 '12 at 13:30
Thank you for the explanation!
– goncalvesnelson
Apr 19 '14 at 19:34
Thank you for the explanation!
– goncalvesnelson
Apr 19 '14 at 19:34
add a comment |
From what I've observed after reading the answer (and using the example provided above), the following is also helpful to understand:
when you execute the command:
(add (int 5) (int 2))
What happens is that the 'add defmulti' is executed thus producing a list:
[Integer Integer]
with that produced, it looks for any 'add defmethod' that is identified with above list i.e.:
(add [Integer Integer])
And passes on the arguments that it received.
Another way of defining the multi methods so as to make the passing of arguments clear is:
(defmulti add (fn [a b] [(type a) (type b)]))
(defmethod add [Integer Integer] [a b] (+ a b))
(defmethod add [String String] [a b] (str a b))
Then run the function as:
(add 12 73)
or
(add "thank" "you")
add a comment |
From what I've observed after reading the answer (and using the example provided above), the following is also helpful to understand:
when you execute the command:
(add (int 5) (int 2))
What happens is that the 'add defmulti' is executed thus producing a list:
[Integer Integer]
with that produced, it looks for any 'add defmethod' that is identified with above list i.e.:
(add [Integer Integer])
And passes on the arguments that it received.
Another way of defining the multi methods so as to make the passing of arguments clear is:
(defmulti add (fn [a b] [(type a) (type b)]))
(defmethod add [Integer Integer] [a b] (+ a b))
(defmethod add [String String] [a b] (str a b))
Then run the function as:
(add 12 73)
or
(add "thank" "you")
add a comment |
From what I've observed after reading the answer (and using the example provided above), the following is also helpful to understand:
when you execute the command:
(add (int 5) (int 2))
What happens is that the 'add defmulti' is executed thus producing a list:
[Integer Integer]
with that produced, it looks for any 'add defmethod' that is identified with above list i.e.:
(add [Integer Integer])
And passes on the arguments that it received.
Another way of defining the multi methods so as to make the passing of arguments clear is:
(defmulti add (fn [a b] [(type a) (type b)]))
(defmethod add [Integer Integer] [a b] (+ a b))
(defmethod add [String String] [a b] (str a b))
Then run the function as:
(add 12 73)
or
(add "thank" "you")
From what I've observed after reading the answer (and using the example provided above), the following is also helpful to understand:
when you execute the command:
(add (int 5) (int 2))
What happens is that the 'add defmulti' is executed thus producing a list:
[Integer Integer]
with that produced, it looks for any 'add defmethod' that is identified with above list i.e.:
(add [Integer Integer])
And passes on the arguments that it received.
Another way of defining the multi methods so as to make the passing of arguments clear is:
(defmulti add (fn [a b] [(type a) (type b)]))
(defmethod add [Integer Integer] [a b] (+ a b))
(defmethod add [String String] [a b] (str a b))
Then run the function as:
(add 12 73)
or
(add "thank" "you")
answered Oct 13 '12 at 13:47
PhilPhil
9263919
9263919
add a comment |
add a comment |
Multimethods helps to call the methods based on params passed. It can call the respective methods based on type of argument/or based on some properties of an argument.
Example 1 Based on type
test=> (defmulti multiply (fn [a b] [(type a) (type b)]))
#'test/multiply
test=> (defmethod multiply [Integer Integer] [a b] (* a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (defmethod multiply [String String] [a b] (str a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (multiply 10 10)
test=> (multiply (int 10) (int 10))
100
test=> (multiply "10" "10")
"1010"
Example 2 Based on property
test=> (defmulti mn (fn[a b] ( < a b ) ))
#'test/mn
test=> (defmethod mn true [a b] (+ a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (defmethod mn false [a b] (- a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (mn 1 2)
3
test=> (mn 2 1)
1
test=> (mn 1 1)
0
add a comment |
Multimethods helps to call the methods based on params passed. It can call the respective methods based on type of argument/or based on some properties of an argument.
Example 1 Based on type
test=> (defmulti multiply (fn [a b] [(type a) (type b)]))
#'test/multiply
test=> (defmethod multiply [Integer Integer] [a b] (* a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (defmethod multiply [String String] [a b] (str a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (multiply 10 10)
test=> (multiply (int 10) (int 10))
100
test=> (multiply "10" "10")
"1010"
Example 2 Based on property
test=> (defmulti mn (fn[a b] ( < a b ) ))
#'test/mn
test=> (defmethod mn true [a b] (+ a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (defmethod mn false [a b] (- a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (mn 1 2)
3
test=> (mn 2 1)
1
test=> (mn 1 1)
0
add a comment |
Multimethods helps to call the methods based on params passed. It can call the respective methods based on type of argument/or based on some properties of an argument.
Example 1 Based on type
test=> (defmulti multiply (fn [a b] [(type a) (type b)]))
#'test/multiply
test=> (defmethod multiply [Integer Integer] [a b] (* a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (defmethod multiply [String String] [a b] (str a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (multiply 10 10)
test=> (multiply (int 10) (int 10))
100
test=> (multiply "10" "10")
"1010"
Example 2 Based on property
test=> (defmulti mn (fn[a b] ( < a b ) ))
#'test/mn
test=> (defmethod mn true [a b] (+ a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (defmethod mn false [a b] (- a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (mn 1 2)
3
test=> (mn 2 1)
1
test=> (mn 1 1)
0
Multimethods helps to call the methods based on params passed. It can call the respective methods based on type of argument/or based on some properties of an argument.
Example 1 Based on type
test=> (defmulti multiply (fn [a b] [(type a) (type b)]))
#'test/multiply
test=> (defmethod multiply [Integer Integer] [a b] (* a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (defmethod multiply [String String] [a b] (str a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (multiply 10 10)
test=> (multiply (int 10) (int 10))
100
test=> (multiply "10" "10")
"1010"
Example 2 Based on property
test=> (defmulti mn (fn[a b] ( < a b ) ))
#'test/mn
test=> (defmethod mn true [a b] (+ a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (defmethod mn false [a b] (- a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (mn 1 2)
3
test=> (mn 2 1)
1
test=> (mn 1 1)
0
answered Nov 12 '18 at 11:12
JaiganeshJaiganesh
92
92
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%2f12872513%2fhow-and-why-is-defmulti-and-defmethod-used-and-what-are-the-advantages%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
Are you able to define what a multimethod is? If not then I'll be happy to explain you
– tgoossens
Oct 13 '12 at 11:42
Here is a question I once asked: cs.stackexchange.com/questions/4660/… I answered my own question as well, this might help you understand what a multimethod is
– tgoossens
Oct 13 '12 at 11:43