Linked

ValueLink objects are small and allow us to compose them in an applicative way so that we can share part of a composite structure among different client objects so that those clients don’t observe any side effect on the ValueLink objects they are currently referencing.

By the way, some applications prefer to have a manager object that handles those links as a whole, hiding the inner machinery that keeps their structure sound. Those managers are called containers.

A ValueLink understands the #asLinkedList message to enclose itself in a LinkedList container

SequenceableCollection subclass: #LinkedList
	instanceVariableNames: 'firstLink lastLink'
	classVariableNames: ''
	package: 'Collections-Sequenceable-Base'

for example,

"CTLinksValueLinkTest, protocol tests"
testAsLinkedList

   ^ self exportSlotsGraphOf: self testSimpleValueLink asLinkedList
../_images/CTLinksValueLinkTest-testAsLinkedList.svg

where

where

Two observations are in order:

  • On one hand, since the slot nextLink hosts either a Link or nil then the latter has to understand

    "UndefinedObject, protocol *Containers-Essentials"
    asLinkedList
    
       ^ LinkedList empty
    

    too and it behaves as follows

    "CTLinksValueLinkTest, protocol tests"
    testNilAsLinkedList
    
       ^ self exportSlotsGraphOf: nil asLinkedList
    
    ../_images/CTLinksValueLinkTest-testNilAsLinkedList.svg
  • On the other hand, since a ValueLink could keep a recursive structure then all the values are kept as well

    "CTLinksValueLinkTest, protocol tests"
    testAsLinkedList4321
    
       ^ self exportSlotsGraphOf: self test4321ValueLinks asLinkedList
    
    ../_images/CTLinksValueLinkTest-testAsLinkedList4321.svg

Additionally, LinkedList objects can be built using other objects than ValueLink ones, for example sending #as: to an Interval,

"CTLinksValueLinkTest, protocol tests"
testAsLinkedListFromInterval

   ^ self exportSlotsGraphOf: ((4 to: 1 by: -1) as: LinkedList)
../_images/CTLinksValueLinkTest-testAsLinkedListFromInterval.svg

where

"Number, protocol *Collections-Sequenceable"
to: stop by: step

   "Answer an Interval from the receiver up to the argument, stop, 
   incrementing by step."

   ^ Interval from: self to: stop by: step

and

SequenceableCollection subclass: #Interval
	instanceVariableNames: 'start stop step'
	classVariableNames: ''
	package: 'Collections-Sequenceable-Base'

"I represent a finite arithmetic progression (a range of number).

Description
--------------------------

I allow to iterate easily on a range of number (for example to manupulate an index) with a define step (by default one by one).

Zero step size is not allowed and will raise an error.

I know at which number I begin, at which number I end and the step.

I work with the Number class. I manipulate some numbers and I can be created from a Number.  

Public API and Key Messages
--------------------------

- I implement most of the classic Iterators as #do: or #collect:.

- #from: to: and #from: to: by:  are my two common contructors. But I am usually created by a message send on Number  (See examples).

Examples 
--------------------------

To create an Interval from 1 to 100 there is many ways:

	Interval from: 1 to: 100
	or
	Interval from: 1 to: 100 by: 1
	
	or from a Number 
	
	1 to: 100 
	or 
	1 to: 100 by: 1
	
	You can also use floats or fractions: 
	
	0.1 to: 0.5 by: 0.01
	or
	1/10 to: 1/2 by: 1/100
	
	NB: both expressions will not give exactly the same result. The first will contains only floats and the second only fractions.
	
 
Internal Representation and Key Implementation Points.
--------------------------

    Instance Variables
	start:		<Number> 	The beginning of the Interval.
	step:		<Number> 	The end of the Interval.
	stop:		<Number> 	The step of the interval. If the step is 3 and we begin at 1 the interval will be 1, 4, 7, 10, 13… until the end."

Moreover, from a SequenceableCollection we can revert back to a ValueLink with,

where #foldr:init: folds by associating to the right,

"SequenceableCollection, protocol *Containers-Essentials"
foldr: aBlock init: init

   | cell |
   cell := init.
   self reverseDo: [ :each | cell := aBlock value: each value: cell ].
   ^ cell

as we can see in the following example

../_images/CTLinksValueLinkTest-testAsValueLink.svg

Using another folding message #inject:into: that associates to the left,

"Collection, protocol enumerating"
inject: thisValue into: binaryBlock

   "Accumulate a running value associated with evaluating the argument, binaryBlock, with the current value of the argument, thisValue, and the receiver as block arguments."

   "( #(1 2 3) inject: 0 into: [ :sum :each | sum + each ] ) >>> 6"

   | nextValue |
   nextValue := thisValue.
   self do: [ :each | 
      nextValue := binaryBlock value: nextValue value: each ].
   ^ nextValue

we obtain a ValueLink that keeps the same elements in reversed order,

"CTLinksValueLinkTest, protocol tests"
testAsValueLinkInjectInto

   | l |
   l := (4 to: 1 by: -1)
           inject: nil
           into: [ :aValueLink :each | each ~~> aValueLink ].
   ^ self exportSlotsGraphOf: l
../_images/CTLinksValueLinkTest-testAsValueLinkInjectInto.svg