c# - Access to F# record base properties without using interface -


f# records cannot inherited, can implement interfaces. example, want create different controllers:

type controllertype =     | basic     | advanced1     | advanced1ram     | advanced1rambattery     | advanced2  // base abstract class type icontroller =     abstract member rom : byte[]     abstract member ``type`` : controllertype  type basiccontroller =     { rom : byte[]       ``type`` : controllertype }     interface icontroller         member this.rom = this.rom         member this.``type`` = this.``type``  type advancedcontroller1 =     { ram : byte[]       rom : byte[]       ``type`` : controllertype }     interface icontroller         member this.rom = this.rom         member this.``type`` = this.``type``  type advancedcontroller2 =     { rommode : byte       rom : byte[]       ``type`` : controllertype }     interface icontroller         member this.rom = this.rom         member this.``type`` = this.``type``  let init ``type`` =     match ``type``     | basic ->         { rom = array.zerocreate 0           ``type`` = basic } :> icontroller     | advanced1 | advanced1ram | advanced1rambattery ->         { ram = array.zerocreate 0           rom = array.zerocreate 0           ``type`` = ``type`` } :> icontroller     | advanced2 ->         { rommode = 0xffuy           rom = array.zerocreate 0           ``type`` = ``type`` } :> icontroller 

i have 2 questions:

  1. when create controller record, need upcast interface. there better way write init function above without :> icontroller each record?
  2. i tried discriminated unions somehow end writing interfance example. interface .net thing, how can rewrite example in functional way, composition rather inheritance?

answer first question: no, cannot rid of upcasting every time. f# doesn't automatic type coercion (which thing), , match branches must have same type. thing coerce manually.

answer second question: discriminated unions represent "closed world assumption" - is, when know number of different cases upfront, , you're not interested in extending them later (your world "closed"). in case, can have compiler make sure working thing handles cases. super powerful applications.

on other hand, need design thing in such way can extended later, possibly external plugin. situation referred "open world assumption". in case, interfaces work. not way.

interfaces nothing more records of functions, exception of method genericity. if you're not interested in generic methods and you're not planning on downcasting specific implementations later (which bad thing anyway), can represent "open world" thing record of functions:

type controller = {     ``type``: controllertype    controlsomething: controllablething -> controlresult } 

now can create different types of controllers providing different controlsomething implementation:

let init ``type`` =     match ``type``     | basic ->         let rom = array.zerocreate 0         { ``type`` = basic           controlsomething = fun c -> makecontrolresult c rom }      | advanced1 | advanced1ram | advanced1rambattery ->         let ram = array.zerocreate 0         let rom = array.zerocreate 0         { ``type`` = ``type``            controlsomething = fun c -> makecontrolresultwithram c rom ram }      | advanced2 ->         let rommode = 0xffuy         let rom = array.zerocreate 0         { ``type`` = ``type``            controlsomething = fun c -> /* whatever */ } 

incidentally, gets rid of upcasting, since of same type. incidentally, code smaller now, since don't have explicitly define different controllers own types.

q: wait, now, how access ram , rom , rommode outside?

a: well, how going interface? going downcast interface specific implementation type, , access fields? if going that, you're "closed world", because handles icontroller needs know implementation types , how work them. if case, better off discriminated union begin with. (like said above, downcasting not idea)

on other hand, if you're not interested in downcasting specific types, means you're interested in consuming functionality controllers implement (this whole idea of interfaces). if case, record of functions sufficient.

finally, if are interested in generic methods, have use interfaces, still don't have declare types, f# has inline interface implementations:

type controller =      abstract member ``type``: controllertype    abstract member genericmethod: 'a -> unit  let init ``type`` =     match ``type``     | basic ->         let rom = array.zerocreate 0         { new controller               member this.``type`` = basic              member this.genericmethod x = /* whatever */ }      // similar other cases 

this little more verbose records, , can't amend them (i.e. no { ... ... } syntax interfaces), if absolutely need generic methods, it's possible.


Comments

Popular posts from this blog

php - Permission denied. Laravel linux server -

google bigquery - Delta between query execution time and Java query call to finish -

python - Pandas two dataframes multiplication? -