User Tools

Site Tools


complexvalues

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
complexvalues [2019/01/04 12:42]
christian [Anatomy of a Value]
complexvalues [2019/01/09 19:18] (current)
christian [Complex Values]
Line 1: Line 1:
-===== Complex ​Values =====+===== Values =====
  
 The Values package is my base library for almost everything I do. It provides Values (as opposed to Objects) which are simple, immutable objects. Values can only be created but never modified. This allows for a functional programming style and simplyfies systems, since much less state has to be maintained. Especially I like to see all structure and details (of complex values) at a glance and the ease of creating test values. The Values package is my base library for almost everything I do. It provides Values (as opposed to Objects) which are simple, immutable objects. Values can only be created but never modified. This allows for a functional programming style and simplyfies systems, since much less state has to be maintained. Especially I like to see all structure and details (of complex values) at a glance and the ease of creating test values.
  
 +Features:
 +  * Values as known in the functional world: immutable and consisting only of values or primitive types. Values do not have an identity and are equal when their elements are equal. A Value always forms a simple tree without loops or references. Instead of mutating objects, values are copied with new elements. Values are created with a constructor taking all elements as arguments.
 +  * Literal: every value can print itself ''​**asSource**''​. This produces a string which, when evaluated, yields the same value. This is great for looking at values and for using it in code. This is only possible in Smalltalk and a few other languages (Lisp).
 +  * Defaults: elements can have a default, so that they can be omited in the constructor. This simplifies systems, since only the relevant data has to be given and the defaults are hidden.
 +  * Named Values: some instances of a value class may be well known and should be use in the code instead of the generic constructor. This feature should be used with caution, since changes will break code using obsolete instances. Currently, only ''​ColorValue''​ uses this for ''​black'',​ ''​white''​ and the RGB and CMY colors.
 ==== Motivation ==== ==== Motivation ====
  
Line 10: Line 15:
  
 Now, I use Values for more than 10 years and I cannot do without it anymore. Most of the classes I define are Values. Objects are used for the "​moving parts",​ the complex stuff. Since Values are so trivial and simple, I do not need to spend much time with them - they just work very reliable. Instead I can concentrate on complicated objects at the heart of the app. By sourcing out functionalities to Values, the systems become simpler. Now, I use Values for more than 10 years and I cannot do without it anymore. Most of the classes I define are Values. Objects are used for the "​moving parts",​ the complex stuff. Since Values are so trivial and simple, I do not need to spend much time with them - they just work very reliable. Instead I can concentrate on complicated objects at the heart of the app. By sourcing out functionalities to Values, the systems become simpler.
 +
 +==== Using Values ====
 +
 +To define a new Value class:
 +  - create a new subclass of Value without instance variables and "​Subclass responsibilities"​ checked
 +  - edit he class method #​localSpecification of the new class
 +    - add a pragma for each instance variable describing the variable
 +  - open the popup menu on the new class and select "add Value methods..."​. This generates all methods.
 +  - edit the class method #example to provide a useful value
 +
 +Done.
 +
 +Now you have:
 +  * a class with the specified instance variables
 +  * an accessor for each variable with the same name
 +  * an initializer with all parameters which sets up a fresh value
 +  * a constructor taking all parameters and the sole caller of the initializer
 +  * (2^^<​numberOfDefaultVariables>​) - 1 optional constructors
 +  * an example
 +
 +Lets have an example for example:
 +<code smalltalk>​
 +Person
 +    name: '​Christian Haider'​
 +    sex: #male
 +    birthday: (Date d: 25 m: 6 y: 1960)
 +</​code>​
 +
 +With it you can:
 +  * create a value with <code smalltalk>​person := Person example</​code>​
 +  * ask for its parts <code smalltalk>​person name  "​returns '​Christian Haider'​ "</​code>​
 +  * print it as code <code smalltalk>​person asSource ​ "​returns
 +'​Person
 +    name: ''​Christian Haider''​
 +    sex: #male
 +    birthday: (Date d: 25 m: 6 y: 1960)' "</​code>​
 +  * get the value from its code <code smalltalk>​person class evaluate: person asSource "​returns a value equal to person"</​code>​
 +  * add fancy access methods like <code smalltalk>​
 +weekdayAtBirth
 +  ^self birthday weekday
 +</​code>​
 +
  
 ==== Anatomy of a Value ==== ==== Anatomy of a Value ====
Line 19: Line 66:
   - sex   - sex
   - birthday   - birthday
 +
 +Each variable has a simple getter method with a comment indicating the class.
 +
 +<code smalltalk>​
 +Person>>​name
 +  "<​String>"​
 +  ^name
 +
 +Person>>​sex
 +  "<​Symbol>"​
 +  ^sex
 +
 +Person>>​birthday
 +  "<​Date>"​
 +  ^birthday
 +</​code>​
  
 The variables are set all at once by an initalizing method which has all initial values as parameters. The variables are set all at once by an initalizing method which has all initial values as parameters.
 The object becomes immutable after initialization and all instance variables are effectively constants. The object becomes immutable after initialization and all instance variables are effectively constants.
 +
 +The parameter names are the concatenated name and its class. This prevents name clashes, is systematic and still readable.
  
 <code smalltalk>​ <code smalltalk>​
-Person>>​initializeName: ​aString ​sex: aBoolean ​birthday: ​aDate +Person>>​initializeName: ​nameString ​sex: sexSymbol ​birthday: ​birthdayDate 
-  name := aString+  name := nameString
-  sex := aBoolean+  sex := sexSymbol
-  birthday := aDate.+  birthday := birthdayDate.
   self beImmutable   self beImmutable
 </​code>​ </​code>​
Line 34: Line 99:
  
 <code smalltalk>​ <code smalltalk>​
-Person class>>​name: ​aString ​sex: aBoolean ​birthday: ​aDate+Person class>>​name: ​nameString ​sex: sexSymbol ​birthday: ​birthdayDate
   | inst |   | inst |
   inst := self new.   inst := self new.
-  inst initializeName: ​aString ​sex: aBoolean ​birthday: ​aDate.+  inst initializeName: ​nameString ​sex: sexSymbol ​birthday: ​birthdayDate.
   ^inst   ^inst
 +</​code>​
 +
 +Every value class has an #example mthod. This serves for test cases and as nice place to copy code from.
 +
 +<code smalltalk>​
 +Person class>>​example
 +  ^Person
 +    name: '​Christian Haider'​
 +    sex: #male
 +    birthday: (Date d: 25 m: 6 y: 1960)
 +</​code>​
 +
 +The initializer,​ the constuctor, the example, the accessor methods and a printer method (not shown) are gernerated from a specification class method containing a list of pragmas defining each variable.
 +
 +<code smalltalk>​
 +Person class>>​localSpecification
 +  <​constant:​ #name class: #​{String}>​
 +  <​constant:​ #sex class: #​{Symbol}>​
 +  <​constant:​ #birthday class: #{Date}>
 +</​code>​
 +
 +=== Defaults ===
 +
 +The simple values above are not very interesting. But when you define defaults for some of the variables, Values become more useful. Lets add a nickname to the specification:​
 +
 +<code smalltalk>​
 +Person class>>​localSpecification
 +  <​constant:​ #name class: #​{String}>​
 +  <​constant:​ #sex class: #​{Symbol}>​
 +  <​constant:​ #bithday class: #{Date}>
 +  <​optional:​ #nickname class: #{String} default: 'self name'>​
 +</​code>​
 +
 +After generating code with: 
 +<code smalltalk>​Person generateMethods</​code>​
 +our example responds to #nickname :
 +
 +<code smalltalk>​
 +Person example nickname ​  "​returns '​Christian Haider'​ ">
 +</​code>​
 +
 +and there is a new constructor available:
 +<code smalltalk>​
 +Person class>>​name:​ nameString sex: sexSymbol birthday: birthdayDate nickname: nicknameString>​
 +</​code>​
 +
 +Now you can specify a nickname:
 +<code smalltalk>​
 +Person name: '​Christian Haider'​ sex: #male birthday: (Date d: 25 m: 6 y: 1960) nickname: '​Chris'>​
 +</​code>​
 +
 +If you use the same parameter as the default, it is ignored
 +<code smalltalk>​
 +Person name: '​Christian Haider'​ sex: #male birthday: (Date d: 25 m: 6 y: 1960) nickname: '​Christian Haider'>​
 +</​code>​
 +because it is equal to
 +<code smalltalk>​
 +Person name: '​Christian Haider'​ sex: #male birthday: (Date d: 25 m: 6 y: 1960)>
 </​code>​ </​code>​
  
complexvalues.1546602132.txt.gz · Last modified: 2019/01/04 12:42 by christian