Skip to content

Making default(DateTime) useable #211

@GULPF

Description

@GULPF

The problem

The invalid default value of DateTime has caused lots of trouble over the years. This RFC is a proposal for making default(DateTime) useable while at the same time avoiding breaking existing code when possible.

default(DateTime) is an invalid Nim value

Because Nim always uses binary 0 as the default value, default(DateTime) is not a valid value according to the type system. DateTime contains two fields that are not valid when initialized to binary 0: DateTime.monthday (int range 1-31) and DateTime.month (enum starting at 1).

default(DateTime) is an invalid DateTime

Even if the above issue is ignored, the default value of DateTime is logically still not a valid value. There are several reasons for this that I won't go into here, but for example the weekday, utcOffset, isDst, and timezones fields might not be logically valid when initialized to their default values.

This is not a problem in itself, but these invalid DateTime values are handled badly in the times module (read: not really handled at all). If default(DateTime) becomes a valid Nim value, then this value should have a well defined behavior when sent to a proc in the times module.

The solution

default(DateTime) is an invalid Nim value

Without nim-lang/Nim#12378 there's no way set the fields to valid values, so the only way to make this work is to make 0 a valid value. I propose to change the type of the problematic fields to int, which would make 0 a valid value again.

To reduce the amount of breakage this change would cause, I propose that #75 is also implemented. This would mean that

  • All fields of DateTime are made private.
  • Getters are added for each field. The getters for month and monthday would convert the field to the correct type before returning it.
  • Deprecated setters are added for each field. They should be deprecated for the reasons described in [RFC] Updating the fields of a DateTime is unsafe #75. The documentation for the times module already has a warning that the fields should not be assigned to.

With these changes, I think the only significant breakage would be that the DateTime(...) built in constructor will no longer work. In my opinion this is just a benefit, since this constructor has never been safe to use anyway.

default(DateTime) is an invalid DateTime

With the above changes, we can easily add a isInitialized or isValid proc that tells if a DateTime is valid. When receiving an invalid DateTime, the procs in the times module should raise a Defect. The exception might be $ since it's used in debug contexts, so it's probably more useful to just return "Uninitialized DateTime". The setters should also be an exception since they would be deprecated anyway.

This would also be a breaking change, but hopefully it wouldn't break much code in practice. It would break any code that constructs an invalid DateTime value and then tries to do something with it without first assigning the fields. This should be rare, at least I cannot imagine a reason to do that.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions