Im not really convinced of this reuse by using traits , personally i think re-use was one of the things promissed by OO that never delivered ( especially cross team) and i would argue the re-use was higher in procedural programming. However we have gotten larger amount of reuse through standard libraries.
The reasons for this IMHO are
While traits are one approach to this the other is just to use small objects with tightly defined functional roles ( ie its more important what they do than what they are) . The data side modelling of objects based on what they are and the use of inheritance IMHO leads to compromise objects trying to server too many masters.
With simple objects I create complex ones according to the following rules
IMHO trying to get reuse into more complex objects is a waste of time since it will rarely match the way the caller wants it which means he may hack about with it etc this is made worse if you want stateless objects. Writing objects to be reusable is also time consuming. Best to just mark as sealed and create new objects and keep interfaces and especially extention methods down to a minimum it will make your code much easier to read and maintain.
The reasons for this IMHO are
- more psychological , not invented here syndrome.
- The code is too broad and does not implement it the way i need it.
While traits are one approach to this the other is just to use small objects with tightly defined functional roles ( ie its more important what they do than what they are) . The data side modelling of objects based on what they are and the use of inheritance IMHO leads to compromise objects trying to server too many masters.
With simple objects I create complex ones according to the following rules
- Inherit if it is of the same type and you expect significant reuse eg DrawColouredCircle from DrawCircle
- If you expect singnificant reuse use an interface which adds a single property . Interfaces with more than 1 method/ property lead to messy code. class DrawColouredCircle : IRquiresColourProvider .
- Create a new object which uses composition for the other objects .
- Lastly use extention methods.
IMHO trying to get reuse into more complex objects is a waste of time since it will rarely match the way the caller wants it which means he may hack about with it etc this is made worse if you want stateless objects. Writing objects to be reusable is also time consuming. Best to just mark as sealed and create new objects and keep interfaces and especially extention methods down to a minimum it will make your code much easier to read and maintain.
Topic tags
- f# × 3656
- compiler × 263
- functional × 199
- c# × 119
- websharper × 112
- classes × 96
- web × 94
- book × 84
- .net × 82
- async × 72
- parallel × 43
- server × 43
- parsing × 41
- testing × 41
- asynchronous × 30
- monad × 28
- ocaml × 26
- tutorial × 26
- haskell × 25
- workflows × 22
- html × 21
- linq × 21
- introduction × 19
- silverlight × 19
- wpf × 19
- fpish × 18
- collections × 14
- pipeline × 14
- templates × 12
- monads × 11
- opinion × 10
- reactive × 10
- plugin × 9
- scheme × 9
- sitelets × 9
- solid × 9
- basics × 8
- concurrent × 8
- deployment × 8
- how-to × 8
- python × 8
- complexity × 7
- javascript × 6
- jquery × 6
- lisp × 6
- real-world × 6
- workshop × 6
- xaml × 6
- conference × 5
- dsl × 5
- java × 5
- metaprogramming × 5
- ml × 5
- scala × 5
- visual studio × 5
- formlets × 4
- fsi × 4
- lift × 4
- sql × 4
- teaching × 4
- alt.net × 3
- aml × 3
- enhancement × 3
- reflection × 3
- blog × 2
- compilation × 2
- computation expressions × 2
- corporate × 2
- courses × 2
- cufp × 2
- enterprise × 2
- entity framework × 2
- erlang × 2
- events × 2
- f# interactive × 2
- fsc × 2
- google maps × 2
- html5 × 2
- http × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- keynote × 2
- list × 2
- mvc × 2
- numeric × 2
- obfuscation × 2
- oop × 2
- packaging × 2
- pattern matching × 2
- pipelines × 2
- rx × 2
- script × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- type × 2
- type provider × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- addin × 1
- agents × 1
- agile × 1
- android × 1
- anonymous object × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net mvc × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- b-tree × 1
- bistro × 1
- bug × 1
- camtasia studio × 1
- canvas × 1
- class × 1
- client × 1
- clojure × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- combinator × 1
- confirm × 1
- constructor × 1
- continuation-passing style × 1
- coords × 1
- coursera × 1
- csla × 1
- css × 1
- data × 1
- database × 1
- declarative × 1
- delete × 1
- dhtmlx × 1
- discriminated union × 1
- distance × 1
- docs × 1
- documentation × 1
- dol × 1
- domain × 1
- du × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- error × 1
- etw × 1
- euclidean × 1
- event × 1
- example × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- fantomas × 1
- fear × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- function × 1
- functional style × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- google × 1
- group × 1
- hash × 1
- history × 1
- hosting × 1
- httpcontext × 1
- https × 1
- hubfs × 1
- ie 8 × 1
- if-doc × 1
- inheritance × 1
- installer × 1
- interpreter × 1
- io × 1
- ios × 1
- ipad × 1
- kendo × 1
- learning × 1
- licensing × 1
- macro × 1
- macros × 1
- maps × 1
- markup × 1
- marshal × 1
- math × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- multidimensional × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- nested × 1
- nested loops × 1
- node × 1
- object relation mapper × 1
- object-oriented × 1
- offline × 1
- option × 1
- orm × 1
- osx × 1
- owin × 1
- paper × 1
- parameter × 1
- performance × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- programming × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- ptvs × 1
- quant × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- real-time × 1
- reference × 1
- restful × 1
- round table × 1
- runtime × 1
- scriptcs × 1
- scripting × 1
- service × 1
- session-state × 1
- sitelet × 1
- stickynotes × 1
- stress × 1
- strong name × 1
- structures × 1
- tdd × 1
- template × 1
- tracing × 1
- tsunamiide × 1
- type inference × 1
- type providers × 1
- upload × 1
- vb × 1
- vb.net × 1
- vector × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio shell × 1
- visualstudio × 1
- web api × 1
- webapi × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- xml × 1
|
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us |
Built with WebSharper |
I've been waiting for a pause after the release of Beta2 to ask the community for help in understanding the potential role of the trait reserved keyword.
While F# excels in many areas, (IMHO) object design is somewhat difficult. I don't have vast experience here, my domain being mainly mathematical in nature, but occasionally I've needed to break a class down into smaller compositional pieces and have found that the lack of implicit interfaces or multiple inheritance has required me to rewrite client code or manually write forwarding members on the refactored classes. I can imagine that for larger class hierarchies this becomes painful.
I do understand the reason behind enforcing explicit interfaces and tend to agree with the design - however having a finer-grained mechanism that allowed rapid, safe and compositional object design would be a great victory for the language.
My current reference for trait design is Nierstrasz and Co. 2005, which states:
In many cases modules and combinators reduce the need for this 'intermediate level of abstraction', but in the case of large, stateful (though not necessarily mutable) objects a fluent mechanism of composition is required.
Traits can be simulated in CLR languages using a combination of interface properties and interface method extensions. It's the responsibility of a class that 'inherits' a trait to implement the fields required by the trait's property interface, but then inherits all the trait's functionality (courtesy of the trait's interface extension methods.) This separation is the key to avoiding the notorious diamond problem.
I've pasted below a simple implementation of Circle example in the introduction to the Nierstrasz paper. As you can see it's rather ungainly. Could the trait keyword help here? What further concerns am I missing? Are there better ideas for implementation of the keyword / the concept? How do traits compare to mixin's?
All answers much appreciated,
Danny
open System type Extension = System.Runtime.CompilerServices.ExtensionAttribute type ICircle = abstract Centre : float * float abstract Radius : float [<AutoOpen; Extension>] module ICircleExtensions = type ICircle with member x.Area = 2. * Math.PI * x.Radius member x.Bounds = let r = x.Radius let x, y = x.Centre (x - r, y - r), ( x + r, y + r) [<Extension>] let Area(x:ICircle) = x.Area [<Extension>] let Bounds(x:ICircle) = x.Bounds type IDrawing = abstract Bounds : (float * float) * (float * float) [<AutoOpen; Extension>] module IDrawingExtensions = type IDrawing with member x.Draw() = printfn "Draw on Bounds of %A" x.Bounds [<Extension>] let Draw(x:IDrawing) = x.Draw() type Circle(centreX: float, centreY:float, radius: float) = interface ICircle with member x.Centre = (centreX, centreY) member x.Radius = radius interface IDrawing with member x.Bounds = (x :> ICircle).Bounds [<AutoOpen>] module CircleExtensions = type Circle with member x.ICircle = (x :> ICircle) member x.IDrawing = (x :> IDrawing) [<AutoOpen>] module Main = let c = Circle( 100., 100., 200. ) do c.IDrawing.Draw() Console.ReadKey() |> ignore