Typed slots for Pharo

Julien Delplanque
May 7 · 7 min read
A reflexive duck, for the sake of illustration. (source)

Slots

Color slots. "{#rgb => InstanceVariableSlot. #cachedDepth => InstanceVariableSlot. #cachedBitPattern => InstanceVariableSlot. #alpha => InstanceVariableSlot}"
slot := Color slotNamed: #rgb.
slot name. "#rgb"
slot read: Color black. "0"
slot read: Color white. "1073741823"
slot read: Color blue. "1023"
slot read: Color green. "1047552"
colorWeModifyWithSlot := Color white.
slot read: colorWeModifyWithSlot. “1073741823”
slot write: 0 to: colorWeModifyWithSlot.
slot read: colorWeModifyWithSlot. “0”

Typed slots

Object subclass: #MockObjectForTypedSlotUsingClass
slots: { #testSlot => TypedSlot type: Integer }
classVariables: { }
package: 'TypedSlot-Class-Tests'
TestCase subclass: #TypedSlotClassDescriptionTest
slots: { }
classVariables: { }
package: 'TypedSlot-Class-Tests'
TypedSlotClassDescriptionTest>>testWriteTo
| testSlot mockObject |
testSlot := MockObjectForTypedSlotUsingClass slotNamed: #testSlot.
mockObject := MockObjectForTypedSlotUsingClass new.

self shouldnt: [ testSlot write: 1 to: mockObject ] raise: TypeViolation.
self assert: (testSlot read: mockObject) equals: 1.

self shouldnt: [ testSlot write: nil to: mockObject ] raise: TypeViolation.
self assert: (testSlot read: mockObject) equals: nil.

self should: [ testSlot write: 'string' to: mockObject ] raise: TypeViolation.
self assert: (testSlot read: mockObject) equals: nil.
#testSlot => TypedSlot type: Integer
TypedSlotClassDescriptionTest>>testCheckObjectType
self shouldnt: [ Integer checkObjectType: 1 ] raise: TypeViolation.
self shouldnt: [ Integer checkObjectType: -1 ] raise: TypeViolation.
self shouldnt: [ Fraction checkObjectType: 1/2 ] raise: TypeViolation.
self shouldnt: [ Fraction checkObjectType: 0.5s02 ] raise: TypeViolation.

self
should: [ Integer checkObjectType: 'string' ]
raise: TypeViolation
withExceptionDo: [ :typeViolation |
self assert: typeViolation expectedType equals: Integer.
self assert: typeViolation objectAttemptedToBeWritten equals: 'string' ].

self
should: [ ScaledDecimal checkObjectType: 1/2 ]
raise: TypeViolation
withExceptionDo: [ :typeViolation |
self assert: typeViolation expectedType equals: ScaledDecimal.
self assert: typeViolation objectAttemptedToBeWritten equals: 1/2 ].

A specific error to model type-violation

Error subclass: #TypeViolation
slots: { #expectedType. #objectAttemptedToBeWritten }
classVariables: { }
package: 'TypedSlot-Errors'
TypeViolation>>expectedType: aType objectAttemptedToBeWritten: object
^ self new
expectedType: aType;
objectAttemptedToBeWritten: object;
yourself

Delegating type-checking to ClassDescription

ClassDescription>>checkObjectType: anObject
(anObject isKindOf: self)
ifFalse: [ (TypeViolation expectedType: self objectAttemptedToBeWritten: anObject) signal ]

Implementing TypedSlot

IndexedSlot subclass: #TypedSlot
slots: { #type }
classVariables: { }
package: 'TypedSlot-Core'
TypedSlot>>initialize
super initialize.
self type: Object
TypedSlot>>definitionStringOn: aStream
aStream
store: self name;
nextPutAll: ' => ';
nextPutAll: self class name;
nextPutAll: ' type: '.
self type printOn: aStream
TypedSlot>>definitionString
^ String streamContents: [ :stream |
self definitionStringOn: stream ]
TypedSlot>>hasSameDefinitionAs: otherSlot^ (super hasSameDefinitionAs: otherSlot) 
and: [ self definitionString = otherSlot definitionString ]
TypedSlot>>= anObject
^ super = anObject and: [ self type = anObject type ]
TypedSlot>>hash
^ super hash bitXor: self type hash
TypedSlot>>checkTypeOfValue: newValue
newValue ifNil: [ ^ self ].

type checkObjectType: newValue
TypedSlot>>write: newValue to: anObject
self checkTypeOfValue: newValue.

^ super write: newValue to: anObject

Optimising read

TypedSlot>>emitValue: methodBuilder
methodBuilder pushInstVar: index.

Conclusion

Acknowledgments

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade