.net - Union or Variant type static dispatch -
i have function takes number of arguments, each of may 1 of set of types.
i can handle dynamically , throw type error if fails, in code snippet directly below rather catch these type errors @ compile time.
function specializingfunction(a) string select case a.gettype case gettype(integer) return "int" case gettype(boolean) return "bool" case else return "__unknown__" ' or throw exception end select end function sub mayfail(a1, a2, a3, a4) console.writeline(specializingfunction(a1)) console.writeline(specializingfunction(a2)) console.writeline(specializingfunction(a3)) console.writeline(specializingfunction(a4)) end sub
i had hoped solve problem using dotnet generics, see final code example in question.
i happy use either: 1. open solution - client code may add further type specializations in c++ code below 2. closed solution - fixed set of allowed types, acheived algebraic data types in (e.g.) haskell or boost::variant in c++
...but interested hear answers both.
#include <string> #include <iostream> using namespace std; string specializedfunction(bool x) { return string("bool"); } std::string specializedfunction(int x) { return string("int"); } template<typename t1, typename t2, typename t3, typename t4> void correctlyresolves(t1 a1, t2 a2, t3 a3, t4 a4) { cout << specializedfunction(a1) << "\n"; cout << specializedfunction(a2) << "\n"; cout << specializedfunction(a3) << "\n"; cout << specializedfunction(a4) << "\n"; } int main() { correctlyresolves(1, true, 3, 4); return 0; }
haskell example
data x = xint int | xbool bool descriminator :: x -> string descriminator (xint a) = "int: " ++ show descriminator (xbool a) = "bool: " ++ show lottaargs :: x -> x -> x -> x -> io () lottaargs b c d = putstrln $ descriminator putstrln $ descriminator b putstrln $ descriminator c putstrln $ descriminator d main = lottaargs (xint 1) (xbool false) (xint 2) (xint 3)
the solution tried 1 below, appears vb attempts instantiate function in generic form (without knowing types t1 - t4). vb therefore gives errors of form "value type 't1' cannot converted 'integer'".
function specializedfunction(a boolean) string return "bool" end function function specializedfunction(a integer) string return "int" end function sub failshorribly(of t1, t2, t3, t4)(a1 t1, a2 t2, a3 t3, a4 t4) console.writeline(specializedfunction(a1)) console.writeline(specializedfunction(a2)) console.writeline(specializedfunction(a3)) console.writeline(specializedfunction(a4)) end sub sub main() failshorribly(1, true, 3, 4) end sub
how best can solve sort of design problem in vb? there appropriate statically-verified union or variant type?
i guess create custom type object
member can constructed 1 of allowed types, not seem elegant, there must better way.
edit: solution
see answer below implementation of wrapper-object based solution
i have implemented solution custom type provides conversions in both directions in order allow me use byref
arguments.
it's pretty verbose, think verbosity major design goal of vb :¬)
it's not perfect still not statically keep track of argument type , therefore provides conversions every possible contained type irrespective of it's actual type is.
i may have @ using generics on top of this.
below implementation of technique on toy int/bool example have been using question:
class allowedargs private a_ object ' can't declare a_ reference ' private sub new() end sub ' public sub new(byref s integer) a_ = s end sub ' public shared widening operator ctype(a integer) allowedargs return new allowedargs(a) end operator ' public shared widening operator ctype(a allowedargs) integer if typeof a.a_ integer return ctype(a.a_, integer) else return 0 end if end operator ' public sub new(byref s boolean) a_ = s end sub ' public shared widening operator ctype(a boolean) allowedargs return new allowedargs(a) end operator ' public shared widening operator ctype(a allowedargs) boolean if typeof a.a_ boolean return ctype(a.a_, boolean) else return false end if end operator ' public overrides function tostring() string select case a_.gettype() case gettype(integer) return "int: " + a_.tostring case gettype(boolean) return "bool: " + a_.tostring.toupper case else return "__this_should_neven_happen__" end select end function ' public sub setfromstring(a string) select case a_.gettype() case gettype(integer) try a_ = integer.parse(a) catch ex exception a_ = 0 end try case gettype(boolean) a_ = if(a.toupper = boolean.truestring.toupper, true, false) case else console.writeline("__oh_dear_this_should_never_happen__") end select end sub ' end class sub actuallyworks(byref a1 allowedargs, byref a2 allowedargs, byref a3 allowedargs, byref a4 allowedargs) ' works fine: console.writeline(a1.tostring()) console.writeline(a2.tostring()) console.writeline(a3.tostring()) console.writeline(a4.tostring()) ' these modifications passed correctly a1.setfromstring("9999") a2.setfromstring("9999") a3.setfromstring("9999") a4.setfromstring("9999") end sub sub main() dim a1 integer = 1 dim a2 integer = 2 dim a3 boolean = true dim a4 integer = 3 actuallyworks(a1, a2, a3, a4) console.writeline("after: " + a1.tostring) console.writeline("after: " + a2.tostring) console.writeline("after: " + a3.tostring) console.writeline("after: " + a4.tostring) console.in.readline() end sub
Comments
Post a Comment