views8
comments
To answer this, you need to first diagram carefully what is dependent on what. Since you are unsure how to mash these two cases together, FIRST write EACH one separately:
Case #1: computeBonus for a regular employee.
Actually sit down, and write code that does what you want for just this one situation (pretend you never heard of sales employees). Also write a test case that creates an employee with a given salary, and then passes that employee to the computeBonus function. Check that you get the expected result.
Case #2: computeBonus for a sales employee.
Now write this version by itself (pretend all employees are sales employees), complete with a test using actual numbers.
-------------------------------
NOW you can look at those two, and see where the commonality is. At that time, it is possible to design a meaningful structure.
I'll jump ahead and say that the key question will be: Does "computeBonus" for "salesEmployee" need access to the "commission" field?
If you don't see how to combine these two, then come back and post your two code snippets, and we'll discuss.
~TMSteve
Thanks for replying to my post! Your comments were helpful.
I guess my question was more about how best to implement sub-typing of records in F#. F# doesn't seem to elegantly support this yet?
So, I feel that I have to resort to using the OO-features of F#, when all I want to do is have records be subtypes of eachother. Conceptually, what I want is this:
type Person = { Name: string ; Age: int}
type Employee \expands/extends/modifies Person\ >= {Name: string; Age : int; EmployeeID : int}
or maybe ... = {EmployeeID : int}
Then, I would like to have some nifty way of passing an Employee record into all the functions that already take a Person record. So, if any of those functions look like this:
let make11YearsOld (p:#Person) =
{p with Age = 11}
Then, it would be cool to have the function return either a Person or a Employee depending on what was passed in.
I don't want to use objects to to represent records. OO makes me type a gob of useless/repetitive code and stuff a bunch of method getters all over the place for no good reason at all. I hate all the interface stuff that distracts me from doing something really basic (creating a record).
I guess there are some articles on the F# Journal from Jon Harrop that seem to address this issue to some extent, but I am interested in any more comments you might have as well just to add more info to the topic.
I guess I *could* maybe go through all my code and replace references to the Person record with an Active Pattern called, say PersonSuperType. Then, my active pattern could match on either ... but that does not solve the problem of "returning" a record of either type, depending on what was passed in.
Ah, now I understand why you referred to this as a copy constructor situation.
Unfortunately, records in F# are simply .NET structs; there is no way to attach additional data to them. Even the ability to augment with members doesn't help, since there is no place to store the additional data. See two approaches (dictionary to associate data, and wrapping data inside a class) in posts 5779 and 5780: [link:cs.hubfs.net]
However, those are both significant work. For contemplation by Don & F# team, I would describe an idealized "wished for" syntax as something like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13
// ----- Desired Feature: Subclassing of Records ------ type Person = { Name: string; Age: int} type Employee extends Person with {EmployeeID : int} let make11YearsOld (p:#Person) = {p with Age = 11} // ----- Usage ----- let p1 = {Name: "Fred"; Age: 2} let p2 = make11YearsOld p1 let p3 = {Name: "Sam"; Age: 21; EmployeeID: 1000} let p4 = make11YearsOld p3 ... convenient access: p4.Name, etc. ...
Here is what it would take to do this using OO today:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
type Person(name: string, age: int) = override it.ToString() = "Person{ name=" + name + ", age=" + age.ToString() + " }" member it.Name = name member it.Age = age abstract NewName: string -> Person default it.NewName name1 = new Person(name1, age) abstract NewAge: int -> Person default it.NewAge age1 = new Person(name, age1) type Employee(name: string, age: int, employeeID: int) = inherit Person(name, age) member it.EmployeeID = employeeID override it.ToString() = "Employee{ name=" + name + ", age=" + age.ToString() + ", employeeID=" + employeeID.ToString() + " }" override it.NewName name1 = new Employee(name1, age, employeeID) :> Person override it.NewAge age1 = new Employee(name, age1, employeeID) :> Person member it.NewEmployeeID employeeID1 = new Employee(name, age, employeeID1) let make11YearsOld (p:#Person) = p.NewAge 11 // ----- Usage ----- let p1 = new Person("Fred", 2) let p2 = make11YearsOld p1 let p3 = new Employee(p1.Name, p1.Age, 1000) let p4 = make11YearsOld p3
I don't see a better way to do this in F# at the moment.
~TMSteve
Remark from nitpicker's corner:
> Unfortunately, records in F# are simply .NET structs
Implementation-wise, they are not. F# records are .NET classes (sealed) - that is, record type is a reference type, not a value type.
I guess that at least means that your syntax is not too difficult for code generation to cope with. However I think that it may affect typing rules in somewhat complicated way.
I do like your syntax though - seems to be rather clean and useful!
Friendly,
Dmitry
Here's an alternate approach, using a DU "Person" to enumerate the kinds of Person's:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
#light (* LarsJo, hubFS#5786. // ----- Desired Feature: Subclassing of Records ------ type Person = { Name: string; Age: int} type Employee extends Person with {EmployeeID: int} let make11YearsOld (p:#Person) = {p with Age = 11} // ----- Usage ----- let p1 = {Name: "Fred"; Age: 2} let p2 = make11YearsOld p1 let p3 = {Name: "Sam"; Age: 21; EmployeeID: 1000} let p4 = make11YearsOld p3 ... convenient access: p4.Name, etc. ... *) // ----- Record + DU implementation ----- type _Person = { Name: string; Age: int } type Person = | PlainPerson of _Person | Employee of _Person * int with member it._Person = match it with | PlainPerson p -> p | Employee (p,id) -> p member it.Name = it._Person.Name member it.Age = it._Person.Age member it.EmployeeID = match it with | Employee (p,id) -> id | _ -> failwith "Person.EmployeeID: Only Employees have an EmployeeID" // This returns an entity similar to "p", // but with "p1" as the new _person-portion. let UpdatePerson (p:Person) (p1:_Person) = match p with | PlainPerson _ -> PlainPerson p1 | Employee (_,id) -> Employee(p1,id) let NewName (p:Person) name = UpdatePerson p {p._Person with Name = name} let NewAge (p:Person) age = UpdatePerson p {p._Person with Age = age} // Q: Is there a compile-time way to enforce that only Employee's // can have employeeID's changed? let NewEmployeeID (p:Person) employeeID1 = match p with | Employee (p,id) -> Employee(p,employeeID1) | _ -> failwith "NewEmployeeID: Only Employees have an EmployeeID" let make11YearsOld (p:Person) = NewAge p 11 // ---------- tests ---------- let ps s = printfn "%s" s let pam msg a = printfn "%s = %A" msg a let p1 = PlainPerson({Name="Fred"; Age=2}) let p2 = make11YearsOld p1 let p3 = Employee(p1._Person, 1000) let p4 = make11YearsOld p3 p1.Name |> pam "p1.Name" p2 |> pam "p2" p4 |> pam "p4" p4.Name |> pam "p4.Name" p4.EmployeeID |> pam "p4.EmployeeID" printf "----- Done: Press any key. -----" System.Console.ReadKey(false) |> ignore
Learning from the previous two approaches, here is an OO approach that is somewhat simplified by using a structure.
Compared to the DU approach:
advantage: EmployeeID & NewEmployeeID usage type checked at compile time;
disadvantage: access to EmployeeID after (UpdatePerson, NewName, or NewAge) needs dynamic cast to Employee.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#light (* LarsJo, hubFS#5786. // ----- Desired Feature: Subclassing of Records ------ type Person = { Name: string; Age: int} type Employee extends Person with {EmployeeID: int} let make11YearsOld (p:#Person) = {p with Age = 11} // ----- Usage ----- let p1 = {Name: "Fred"; Age: 2} let p2 = make11YearsOld p1 let p3 = {Name: "Sam"; Age: 21; EmployeeID: 1000} let p4 = make11YearsOld p3 ... convenient access: p4.Name, etc. ... *) // ----- Record + OO implementation ----- type _Person = { Name: string; Age: int } // NOTE: Gives "abstract" warning. type Person(p: _Person) = member it._Person = p member it.Name = p.Name member it.Age = p.Age abstract UpdatePerson: _Person -> Person member it.NewName name1 = it.UpdatePerson {p with Name=name1} member it.NewAge age1 = it.UpdatePerson {p with Age=age1} type PlainPerson(p: _Person) = inherit Person(p) override it.UpdatePerson p = new PlainPerson(p) :> Person override it.ToString() = "PlainPerson" + any_to_string p type Employee(p: _Person, employeeID: int) = inherit Person(p) member it.EmployeeID = employeeID override it.UpdatePerson p = new Employee(p,employeeID) :> Person member it.NewEmployeeID id1 = new Employee(p,id1) override it.ToString() = "Employee{ " + any_to_string p + "; EmployeeID=" + employeeID.ToString() + " }" let make11YearsOld (p:#Person) = p.NewAge 11 // ---------- tests ---------- let ps s = printfn "%s" s let pam msg a = printfn "%s = %A" msg a let p1 = PlainPerson({Name="Fred"; Age=2}) let p2 = make11YearsOld p1 let p3 = Employee(p1._Person, 1000) let p4 = make11YearsOld p3 :?> Employee // dynamic cast p1.Name |> pam "p1.Name" p2 |> pam "p2" p4 |> pam "p4" p4.Name |> pam "p4.Name" p4.EmployeeID |> pam "p4.EmployeeID" printf "----- Done: Press any key. -----" System.Console.ReadKey(false) |> ignore
I *really* like your idealized syntax. The other approaches and threads you pointed out were really helpful too. At least, I know that other people are running into the same problem.
I wonder what the theoretical problems would be as far as adding it to the record syntax.
I don't see an easy way to add it to the current implementation of a record, which is a .NET structure.
I suspect that on .NET, the way to implement it would be to turn extensible record types into classes behind the scenes. Reason: using classes would give a way to clone an object having the correct fields. This is just an implementation detail; they would look just like normal records to the programmer.
This is a general theme of mine: discriminated unions and records provide convenient concise syntax, but have limited extensibility; I would like an extensible version of these, and it looks like implementing internally as classes would be an effective technique on .NET. Just hide all that from the programmer.
Unfortunately, I don't see any way to avoid one annoyance: at the time a record is created, there would have to be some keyword you use to say that it is permitted to be extended. Reason: the current implementation is high performance and compact; don't want to burden ALL record types with the cost of being extensible.
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
I'm working with a "copy constructor" problem, I think:
Lets say I have an employee file that has a single field called "salary". I also have a function "computeBonus" that takes an employee record and "extends" it into a HappyEmployee file that has two fields: salary AND bonus. So, "computeBonus" KNOWs how to compute the field "bonus" and thus extend an Employee into a HappyEmployee.
Now, lets say I want to actually pass in a *sales* employee file into my "computeBonus" function instead. A sales employee certainly "has" a salary, but ALSO a "commission" field. The result of calling "computeBonus" on a SalesEmployee should be a file that has a sales, bonus, AND commission.
What is the right way to represent this (data structures, records, interface, types, code-reuse)?