Typed slots for Pharo

A reflexive duck, for the sake of illustration. (source)

Slots

I’m a meta-object for accessing a slot in an Object.

I define a protocol to read (#read:) and to write (#write:to:) values.

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 ].
Error subclass: #TypeViolation
slots: { #expectedType. #objectAttemptedToBeWritten }
classVariables: { }
package: 'TypedSlot-Errors'
TypeViolation>>expectedType: aType objectAttemptedToBeWritten: object
^ self new
expectedType: aType;
objectAttemptedToBeWritten: object;
yourself
ClassDescription>>checkObjectType: anObject
(anObject isKindOf: self)
ifFalse: [ (TypeViolation expectedType: self objectAttemptedToBeWritten: anObject) signal ]
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
TypedSlot>>emitValue: methodBuilder
methodBuilder pushInstVar: index.

Conclusion

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store