I have exactly the same requirement. Additionally, I often have more than 2 fields and also change the fields of my custom types.
So I use a slightly more general version of the above: function CompositeBinaryOp(T::Symbol, op::Symbol) expressions = [ :($op(x1.$field, x2.$field)) for field in fieldnames(eval(T)) ] body = Expr(:call, T, expressions...) quote function $op(x1::$T, x2::$T) return $body end end end type M a b end import Base: +, -, *, /, ^ for T in [:M] for op in [:+, :-, :*, :/, :^] #eval(CompositeBinaryOp(T, op)) code = CompositeBinaryOp(T, op) println(code, "\n") eval(code) end end The advantage here for me is that I can change the fields (number, type order etc.) and operators don't need manual updating. I have similar functions for copy constructors, unary operators etc.