[squeak-dev] The Inbox: Chronology-Core-ul.54.mcz

Chris Muller asqueaker at gmail.com
Mon May 4 23:00:23 UTC 2020


It seems like this new API actually broadens the burden on the user to have
to reckon with the internal private attribute of Chronology -- its
underlying epoch.  I just want something that provides efficient access to
the precision already present in the domain, but not increase the API
surface area with additional concerns the user should not have to care
about, and which further break encapsulation.

So, I'm -1 on this as-is.  I really think we need a better solution
that moves toward Chronology being more encapsulated, instead of less.

Best,
  Chris

On Mon, May 4, 2020 at 5:19 PM Chris Muller <asqueaker at gmail.com> wrote:

> Hi Levente,
>
> This at least provides my bare-minimum requirement to be able capture
> "now" efficiently, thread-safely, and without garbage.
>
> However, it still suffers, at least as badly, from that API pimple that is
> not only misleading but even insidious from the aspect that it would
> silently calculate wrong values if used in the "obvious" way.  Please "zoom
> out" and look at the API as a whole, the nomenclature it's employing, and
> *pretend you're a new user interpreting it for the first time*.  You would
> see:
>
>      Time class>>#utcMicrosecondClock
>      Time class>>#posixUtcMicrosecondClock
>
> one of which can be used with the constructor on DateAndTime, which is:
>
>     DateAndTime class>>#utcMicroseconds:offset:
>
> There's not even a comment on that method.  So which one is the new user
> going to use?  And when should the offset: argument be other than 0 when
> doing that use-case?  These questions reveal a "hole" in the API, IMO.
>
> You at least agreed this dichotomy is "unfortunate" -- so why can't we fix
> it?  I don't believe your worries about "backward compatibility".
> Benchmarks don't care where they start, just the delta.  Plus, you never
> objected to prior API's, renames, or even the introduction of very
> incompatible UTCDateAndTime in the first place.  It's just a little work
> (and if you feel it's "bad" API, why would you have any senders anyway?).
> Literally, just the other day, I went though > 150(!) test cases just to
> change a bunch of senders from #includesSubString: to #includesSubstring:.
> Ring a bell?  You're right, it was boring, and my hands were aching
> afterward, but I wouldn't even consider asking you or anyone here to keep
> Squeak held back because of that.  You said you don't find the API
> fantastic, but this doesn't seem any more serious than that, so why not
> improve it?
>
> There are other ways to fix it (e.g., rename #utcMicroseconds:offset: to
> #posixUtcMicroseconds:offset:).  I don't really care how we fix it but,
> IMO, we really should.  Squeak has very smart implementors, but IMO, we
> should care more about  -- d e s i g n --  and UX.  People say Steve Jobs
> was a "jerk," but I think it may be he just cared a lot about UX but found
> himself among those who didn't.
>
>  - Chris
>
> On Sun, May 3, 2020 at 1:45 PM <commits at source.squeak.org> wrote:
>
>> Levente Uzonyi uploaded a new version of Chronology-Core to project The
>> Inbox:
>> http://source.squeak.org/inbox/Chronology-Core-ul.54.mcz
>>
>> ==================== Summary ====================
>>
>> Name: Chronology-Core-ul.54
>> Author: ul
>> Time: 3 May 2020, 8:45:27.099465 pm
>> UUID: 770bbc91-fb33-46c2-a283-57f7163b672e
>> Ancestors: Chronology-Core-nice.52
>>
>> Automatically update the time zone cached by the VM every 30 minutes:
>> - copied and modified Eliot's accessor to primitive 243 to do the actual
>> updating (Time class >> #primitiveUpdateTimeZone)
>> - update happens when Time class >> #posixMicrosecondClockWithOffset or
>> Time class >> #posixMicrosecondClockWithOffset: are sent. Other low-level
>> accessors of the VM time zone are not updating the cached time zone value
>> (e.g. Time class >> #localMicrosecondClockPrimitive)
>> - actual update happens in Time class >> #updateTimeZoneCacheAt:
>> - postscript activates the update mechanism which can be turned off by
>> evaluating [ Time classPool at: #UpdateVMTimeZoneCacheAt put: nil ]
>>
>> Other changes:
>> - added Time class >> #posixUtcMicrosecondClock to have a fast way to
>> access that raw timestamp
>> - added MicrosecondsBetweenPosixEpochAndSqueakEpoch to
>> ChronologyConstants to support the above
>> - do not send Time class >> #initialize from DateAndTime class >>
>> #startUp:. Let Time have its own #startUp: method instead. Postscript adds
>> Time to the startUpList before DateAndTime.
>> - do not send super initialize from DateAndTime class >> #initialize
>> - do not send #automaticTimezone to DateAndTime on startup, because
>> that's just an accessor with no side effects
>> - do not overwrite set variables in Time class >> #initialize
>> - assert that the value passed to Time class >> #clockPolicy: is one of
>> the known values
>>
>> =============== Diff against Chronology-Core-nice.52 ===============
>>
>> Item was changed:
>>   SharedPool subclass: #ChronologyConstants
>>         instanceVariableNames: ''
>> +       classVariableNames: 'DayNames DaysInMonth
>> MicrosecondsBetweenPosixEpochAndSqueakEpoch MicrosecondsInDay MonthNames
>> NanosInMillisecond NanosInSecond OneDay SecondsInDay SecondsInHour
>> SecondsInMinute SqueakEpoch Zero'
>> -       classVariableNames: 'DayNames DaysInMonth MicrosecondsInDay
>> MonthNames NanosInMillisecond NanosInSecond OneDay SecondsInDay
>> SecondsInHour SecondsInMinute SqueakEpoch Zero'
>>         poolDictionaries: ''
>>         category: 'Chronology-Core'!
>>
>>   !ChronologyConstants commentStamp: 'brp 3/12/2004 14:34' prior: 0!
>>   ChronologyConstants is a SharedPool for the constants used by the
>> Kernel-Chronology classes.!
>>
>> Item was changed:
>>   ----- Method: ChronologyConstants class>>initialize (in category 'class
>> initialization') -----
>>   initialize
>>         "ChronologyConstants initialize"
>>
>>         SqueakEpoch := 2415386.                 "Julian day number of 1
>> Jan 1901"
>>         SecondsInDay := 86400.
>>         SecondsInHour := 3600.
>>         SecondsInMinute := 60.
>>         MicrosecondsInDay := 24 * 60 * 60 * 1000000.
>>         NanosInSecond := 10 raisedTo: 9.
>>         NanosInMillisecond := 10 raisedTo: 6.
>>         DayNames := #(Sunday Monday Tuesday Wednesday Thursday Friday
>> Saturday).
>>
>>         MonthNames := #(        January February March April May June
>>                                                 July August September
>> October November December).
>> +       DaysInMonth := #(31 28 31 30 31 30 31 31 30 31 30 31).
>> +       MicrosecondsBetweenPosixEpochAndSqueakEpoch := 2177452800000000!
>> -       DaysInMonth := #(31 28 31 30 31 30 31 31 30 31 30 31)!
>>
>> Item was changed:
>>   ----- Method: DateAndTime class>>initialize (in category
>> 'initialize-release') -----
>>   initialize
>>
>> -       super initialize.
>> -
>>         ClockProvider := Time.
>>         PosixEpochJulianDays := 2440588.
>>         InitializeFromPrimitive := self canInitializeFromPrimitive.
>>         Smalltalk addToStartUpList: self.
>>         self startUp: true
>>   !
>>
>> Item was changed:
>>   ----- Method: DateAndTime class>>startUp: (in category 'system
>> startup') -----
>>   startUp: startingAfresh
>>         "Set local timezone"
>>         startingAfresh
>>                 ifTrue: [InitializeFromPrimitive := self
>> canInitializeFromPrimitive.
>>                         Time initialize. "set LastClockTick to 0".
>> +                       self now]!
>> -                       self now.
>> -                       self automaticTimezone]!
>>
>> Item was changed:
>>   Magnitude subclass: #Time
>>         instanceVariableNames: 'seconds nanos'
>> +       classVariableNames: 'ClockPolicy HighResClockTicksPerMillisecond
>> LastClockTick UpdateVMTimeZoneCacheAt UseHighResClockForTiming'
>> -       classVariableNames: 'ClockPolicy HighResClockTicksPerMillisecond
>> LastClockTick UseHighResClockForTiming'
>>         poolDictionaries: 'ChronologyConstants'
>>         category: 'Chronology-Core'!
>>
>>   !Time commentStamp: 'dew 10/23/2004 17:58' prior: 0!
>>   This represents a particular point in time during any given day.  For
>> example, '5:19:45 pm'.
>>
>>   If you need a point in time on a particular day, use DateAndTime.  If
>> you need a duration of time, use Duration.
>>   !
>>
>> Item was changed:
>>   ----- Method: Time class>>clockPolicy: (in category 'class
>> initialization') -----
>>   clockPolicy: aSymbol
>>         "When sequencial calls are made to DateAndTime now, it may be
>> desirable to
>>         force the system clock to be monotonic, and it may be desirable
>> for the clock
>>         to appear to be strictly increasing with no repeat values. The
>> ClockPolicy
>>         identifies which of several possible strategies to use.
>>
>>         Allowable values are
>>                 #acceptPlatformTime
>>                 #monotonicAllowDuplicates
>>                 #monotonicForceMicrosecondIncrement
>>                 #monotonicForceNanosecondIncrement "
>>
>> +       self assert: (
>> +               #(
>> +                       acceptPlatformTime
>> +                       monotonicAllowDuplicates
>> +                       monotonicForceMicrosecondIncrement
>> +                       monotonicForceNanosecondIncrement) includes:
>> aSymbol).
>>         ClockPolicy := aSymbol!
>>
>> Item was changed:
>>   ----- Method: Time class>>initialize (in category 'class
>> initialization') -----
>>   initialize
>> +       " self initialize "
>> -       "Time initialize"
>>
>> +       LastClockTick ifNil: [ LastClockTick := 0 ].
>> -       "Initialize at startup time to protect for the case of an image
>> saved with bad LastClockTick"
>> -       LastClockTick := 0.
>>
>> +       HighResClockTicksPerMillisecond ifNil: [
>> HighResClockTicksPerMillisecond := 0 ].
>> -       HighResClockTicksPerMillisecond := 0.
>>
>> +       ClockPolicy ifNil: [
>> +               "self clockPolicy: #acceptPlatformTime."
>> +               self clockPolicy: #monotonicAllowDuplicates.
>> +               "self clockPolicy: #monotonicForceMicrosecondIncrement."
>> +               "self clockPolicy: #monotonicForceNanosecondIncrement." ]!
>> -       "self clockPolicy: #acceptPlatformTime."
>> -       self clockPolicy: #monotonicAllowDuplicates.
>> -       "self clockPolicy: #monotonicForceMicrosecondIncrement."
>> -       "self clockPolicy: #monotonicForceNanosecondIncrement."
>> - !
>>
>> Item was changed:
>>   ----- Method: Time class>>posixMicrosecondClockWithOffset (in category
>> 'clock') -----
>>   posixMicrosecondClockWithOffset
>>         "Answer an array with local microseconds since the Posix epoch
>> and the
>>         current seconds offset from GMT in the local time zone."
>>
>> +       | array posixUtcValue |
>> -       | array utcValue |
>>         array := self primPosixMicrosecondClockWithOffset.
>> +       posixUtcValue := array at: 1.
>> +       (self updateTimeZoneCacheAt: posixUtcValue) ifTrue: [ "Time zone
>> may have changed: fetch again."
>> +               self primPosixMicrosecondClockWithOffset: array.
>> +               posixUtcValue := array at: 1 ].
>>         ClockPolicy caseOf: {
>>                 [#acceptPlatformTime] -> [^ array] .
>>                 [#monotonicAllowDuplicates] -> [
>> +                       posixUtcValue > LastClockTick
>> +                               ifTrue: [LastClockTick := posixUtcValue]
>> -                       utcValue := array at: 1.
>> -                       utcValue > LastClockTick
>> -                               ifTrue: [LastClockTick := utcValue]
>>                                 ifFalse: [array at: 1 put:
>> LastClockTick]] .
>>                 [#monotonicForceMicrosecondIncrement] -> [
>> +                       posixUtcValue > LastClockTick
>> +                               ifTrue: [LastClockTick := posixUtcValue]
>> -                       utcValue := array at: 1.
>> -                       utcValue > LastClockTick
>> -                               ifTrue: [LastClockTick := utcValue]
>>                                 ifFalse: [LastClockTick := LastClockTick
>> + 1. "add one microsecond"
>>                                         array at: 1 put: LastClockTick]] .
>>                 [#monotonicForceNanosecondIncrement] -> [
>> +                       posixUtcValue > LastClockTick
>> +                               ifTrue: [LastClockTick := posixUtcValue]
>> -                       utcValue := array at: 1.
>> -                       utcValue > LastClockTick
>> -                               ifTrue: [LastClockTick := utcValue]
>>                                 ifFalse: [LastClockTick := LastClockTick
>> + (1 / 1000). "add one nanosecond"
>>                                         array at: 1 put: LastClockTick]]
>>         } otherwise: [].
>> +       ^array!
>> -       ^array
>> -
>> - !
>>
>> Item was changed:
>>   ----- Method: Time class>>posixMicrosecondClockWithOffset: (in category
>> 'clock') -----
>>   posixMicrosecondClockWithOffset: aDateAndTime
>>         "Initialize aDateAndTime initialized with local microseconds
>> since the Posix
>>         epoch and the current seconds offset from GMT in the local time
>> zone."
>>
>> +       | posixUtcValue |
>> -
>> -       | utcValue |
>>         self primPosixMicrosecondClockWithOffset: aDateAndTime.
>> +       posixUtcValue := aDateAndTime utcMicroseconds.
>> +       (self updateTimeZoneCacheAt: posixUtcValue) ifTrue: [ "Time zone
>> may have changed: fetch again."
>> +               self primPosixMicrosecondClockWithOffset: aDateAndTime .
>> +               posixUtcValue := aDateAndTime utcMicroseconds ].
>>         ClockPolicy caseOf: {
>>                 [#acceptPlatformTime] -> [^ aDateAndTime] .
>>                 [#monotonicAllowDuplicates] -> [
>> +                       posixUtcValue > LastClockTick
>> +                               ifTrue: [LastClockTick := posixUtcValue]
>> -                       utcValue := aDateAndTime utcMicroseconds.
>> -                       utcValue > LastClockTick
>> -                               ifTrue: [LastClockTick := utcValue]
>>                                 ifFalse: [aDateAndTime utcMicroseconds:
>> LastClockTick]] .
>>                 [#monotonicForceMicrosecondIncrement] -> [
>> +                       posixUtcValue > LastClockTick
>> +                               ifTrue: [LastClockTick := posixUtcValue]
>> -                       utcValue := aDateAndTime utcMicroseconds.
>> -                       utcValue > LastClockTick
>> -                               ifTrue: [LastClockTick := utcValue]
>>                                 ifFalse: [LastClockTick := LastClockTick
>> + 1. "add one microsecond"
>>                                         aDateAndTime utcMicroseconds:
>> LastClockTick]] .
>>                 [#monotonicForceNanosecondIncrement] -> [
>> +                       posixUtcValue > LastClockTick
>> +                               ifTrue: [LastClockTick := posixUtcValue]
>> -                       utcValue := aDateAndTime utcMicroseconds.
>> -                       utcValue > LastClockTick
>> -                               ifTrue: [LastClockTick := utcValue]
>>                                 ifFalse: [LastClockTick := LastClockTick
>> + (1 / 1000). "add one nanosecond"
>>                                         aDateAndTime utcMicroseconds:
>> LastClockTick]]
>>         } otherwise: [].
>> +       ^aDateAndTime!
>> -       ^aDateAndTime
>> - !
>>
>> Item was added:
>> + ----- Method: Time class>>posixUtcMicrosecondClock (in category
>> 'clock') -----
>> + posixUtcMicrosecondClock
>> +       "Answer the UTC microseconds since the POSIX epoch (January 1st
>> 1970 00:00:00 UTC)."
>> +
>> +       ^self utcMicrosecondClock -
>> MicrosecondsBetweenPosixEpochAndSqueakEpoch!
>>
>> Item was added:
>> + ----- Method: Time class>>primitiveUpdateTimeZone (in category 'clock')
>> -----
>> + primitiveUpdateTimeZone
>> +       "Update the VMs notion of the current time zone.  The VM sets its
>> notion
>> +        of the time zone once at start-up.  If one wants the VM to keep
>> its notion
>> +        up-to-date arrange to invoke this primitive periodically."
>> +
>> +       <primitive: 243>
>> +       ^nil "Return nil instead of self to indicate that the primitive
>> failed."!
>>
>> Item was added:
>> + ----- Method: Time class>>startUp: (in category 'system startup') -----
>> + startUp: resuming
>> +
>> +       resuming ifTrue: [
>> +               LastClockTick := 0 ]!
>>
>> Item was added:
>> + ----- Method: Time class>>updateTimeZoneCacheAt: (in category 'clock')
>> -----
>> + updateTimeZoneCacheAt: posixUtcMicrosecondClock
>> +       "Tell the VM to update its cached time zone value if the POSIX
>> UTC time reached the valute stored in UpdateVMTimeZoneCacheAt has been
>> reached. Assume that posixUtcMicrosecondClock is an integer with the
>> current POSIX UTC microsecond clock value. Return true when the cache was
>> updated to indicate that the time zone may have changed."
>> +
>> +       | updateInterval |
>> +       UpdateVMTimeZoneCacheAt ifNil: [
>> +               "Automatic update is disabled."
>> +               ^false ].
>> +       posixUtcMicrosecondClock < UpdateVMTimeZoneCacheAt ifTrue: [
>> ^false ].
>> +       self primitiveUpdateTimeZone ifNil: [
>> +               "The primitive failed."
>> +               ^false ].
>> +       updateInterval := 1800000000. "This could be a preference but 30
>> minutes matches all upcoming DST change times."
>> +       UpdateVMTimeZoneCacheAt := posixUtcMicrosecondClock //
>> updateInterval + 1 * updateInterval "Round up posixUtcMicrosecondClock to
>> the next multiple of updateInterval.".
>> +       ^true!
>>
>> Item was changed:
>> + (PackageInfo named: 'Chronology-Core') postscript: '"Make sure
>> UpdateVMTimeZoneCacheAt of Time is initialized."
>> + Time classPool at: #UpdateVMTimeZoneCacheAt put: 0.
>> + "Separated Time''s startup duties from DateAndTime."
>> + Smalltalk addToStartUpList: Time before: DateAndTime'!
>> - (PackageInfo named: 'Chronology-Core') postscript: 'DateAndTime
>> startUp: true.
>> - HashedCollection rehashAll.
>> - '!
>>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20200504/1256fbea/attachment-0001.html>


More information about the Squeak-dev mailing list