Thread overview
Why is SysTime.init invalid?
Apr 01, 2014
ed
Apr 01, 2014
ed
Apr 01, 2014
Jonathan M Davis
Apr 01, 2014
ed
Apr 03, 2014
Jonathan M Davis
Apr 03, 2014
ed
April 01, 2014
Hi All,


I'm trying to use SysTime in a struct but I've noticed the following:

(A) SysTime.init leads to a crash.
---
void main()
{
    SysTime t;
    writefln("t:%s", t);
}

% ./dtest
zsh: segmentation fault (core dumped) ./dtest
---

(B) Initialising a SysTime member directly fails
---
struct T
{
    SysTime t=SysTime(0);
}
datetime.d (28538) Error: static variable _lowLock cannot be read at compile time
---

Which means I have to provide a default ctor for my struct but do not know how.


1. Is this by design or is it a bug?
2. Is there a way to provide a default struct ctor so I can init the SysTime member?

If this is by design I don't think it should crash. A Date/Time error is often something user code can safely recover from.

Thanks,
ed
April 01, 2014
OK, lazy me just read the std.satetime article again. It appears the design is for no invalid values and it is currently a known limitation due to CTFE.

---
d_time_nan	There is no equivalent. SysTime.init, which has a null TimeZone object, would be the closest, but once CTFE advances to the point that you can new up class objects with it, SysTime.init's timezone will be LocalTime, so don't rely on SysTime.init being invalid. std.datetime in general tries to avoid having any invalid states for any of its types. It's intended that creating such values be impossible.
---

I would still like to know if there is a way around this so I can have my struct default init.

Thanks,
ed

April 01, 2014
On Tuesday, April 01, 2014 05:35:28 ed wrote:
> OK, lazy me just read the std.satetime article again. It appears the design is for no invalid values and it is currently a known limitation due to CTFE.
> 
> ---
> d_time_nan	There is no equivalent. SysTime.init, which has a null
> TimeZone object, would be the closest, but once CTFE advances to
> the point that you can new up class objects with it,
> SysTime.init's timezone will be LocalTime, so don't rely on
> SysTime.init being invalid. std.datetime in general tries to
> avoid having any invalid states for any of its types. It's
> intended that creating such values be impossible.
> ---
> 
> I would still like to know if there is a way around this so I can have my struct default init.

You can certainly have a struct with a SysTime member, but there's no way for it to use that SysTime without first assigning a valid value to it - at least, not without segfaulting when it tries to use the SysTime in any context which it would use its timezone member.

If you really want to have the SysTime be useable in the init value of your struct, then you can make it so that each of its member functions which use the SysTime member check it for validity first (or have a separate bool which indicates whether the SysTime has been assigned to or not), in which case, it could assign something like SysTime(0) to it, which would be the valid equivalent of SysTime.init.

Unfortunately, that does add extra overhead, but there isn't any way around it if you want to have the SysTime be used without having the user of the struct assign to it first. It's pretty much the same boat that SysTime itself is in. I could make it so that it checks the timezone for null every time it's used and assign LocalTime to it if it's null, but that adds constant overhead. My decision was that it was better to just live with the fact that SysTime.init is invalid. It's debatable though, as it's a trade-off.

- Jonathan M Davis
April 01, 2014
On Tuesday, 1 April 2014 at 10:54:41 UTC, Jonathan M Davis wrote:
> On Tuesday, April 01, 2014 05:35:28 ed wrote:
>> OK, lazy me just read the std.satetime article again. It appears
>> the design is for no invalid values and it is currently a known
>> limitation due to CTFE.
>> 
>> ---
>> d_time_nan	There is no equivalent. SysTime.init, which has a null
>> TimeZone object, would be the closest, but once CTFE advances to
>> the point that you can new up class objects with it,
>> SysTime.init's timezone will be LocalTime, so don't rely on
>> SysTime.init being invalid. std.datetime in general tries to
>> avoid having any invalid states for any of its types. It's
>> intended that creating such values be impossible.
>> ---
>> 
>> I would still like to know if there is a way around this so I can
>> have my struct default init.
>
> You can certainly have a struct with a SysTime member, but there's no way for
> it to use that SysTime without first assigning a valid value to it - at least,
> not without segfaulting when it tries to use the SysTime in any context which
> it would use its timezone member.
>
> If you really want to have the SysTime be useable in the init value of your
> struct, then you can make it so that each of its member functions which use
> the SysTime member check it for validity first (or have a separate bool which
> indicates whether the SysTime has been assigned to or not), in which case, it
> could assign something like SysTime(0) to it, which would be the valid
> equivalent of SysTime.init.
>
> Unfortunately, that does add extra overhead, but there isn't any way around it
> if you want to have the SysTime be used without having the user of the struct
> assign to it first. It's pretty much the same boat that SysTime itself is in.
> I could make it so that it checks the timezone for null every time it's used
> and assign LocalTime to it if it's null, but that adds constant overhead. My
> decision was that it was better to just live with the fact that SysTime.init
> is invalid. It's debatable though, as it's a trade-off.
>
> - Jonathan M Davis

I have changed my code slightly to what you suggest, assigning SysTime(0) if not initialised. It wasn't a big change and works fine.

Thanks,
ed
April 03, 2014
On Tuesday, April 01, 2014 03:54:07 Jonathan M Davis wrote:
> On Tuesday, April 01, 2014 05:35:28 ed wrote:
> > OK, lazy me just read the std.satetime article again. It appears the design is for no invalid values and it is currently a known limitation due to CTFE.
> > 
> > ---
> > d_time_nan	There is no equivalent. SysTime.init, which has a null
> > TimeZone object, would be the closest, but once CTFE advances to
> > the point that you can new up class objects with it,
> > SysTime.init's timezone will be LocalTime, so don't rely on
> > SysTime.init being invalid. std.datetime in general tries to
> > avoid having any invalid states for any of its types. It's
> > intended that creating such values be impossible.
> > ---
> > 
> > I would still like to know if there is a way around this so I can have my struct default init.
> 
> You can certainly have a struct with a SysTime member, but there's no way for it to use that SysTime without first assigning a valid value to it - at least, not without segfaulting when it tries to use the SysTime in any context which it would use its timezone member.
> 
> If you really want to have the SysTime be useable in the init value of your struct, then you can make it so that each of its member functions which use the SysTime member check it for validity first (or have a separate bool which indicates whether the SysTime has been assigned to or not), in which case, it could assign something like SysTime(0) to it, which would be the valid equivalent of SysTime.init.
> 
> Unfortunately, that does add extra overhead, but there isn't any way around it if you want to have the SysTime be used without having the user of the struct assign to it first. It's pretty much the same boat that SysTime itself is in. I could make it so that it checks the timezone for null every time it's used and assign LocalTime to it if it's null, but that adds constant overhead. My decision was that it was better to just live with the fact that SysTime.init is invalid. It's debatable though, as it's a trade-off.

Actually, after thinking about this more after someone opened a bug on the fact that SysTime.init.toString() segfaults (since the timezone is null)

https://d.puremagic.com/issues/show_bug.cgi?id=12507

I think that I have a solution. It's now possible to default-intialize the timezonet to UTC so that SysTime.init is equivalent to SysTime(0, UTC()). It's not ideal, because it's not SysTime(0, LocalTime()), and SysTime normally defaults to LocalTime, but it will never be possible to default-initialize it to LocalTime thanks to the fact that it has to call tzset when it's initialized.

You can look my comments in the bug for more details. I've opened a pull request with those changes, so the next release will probably have a valid SysTime.init, even if it's not SysTime(0, LocalTime()) like would be ideal.

- Jonathan M Davis
April 03, 2014
On Thursday, 3 April 2014 at 06:23:40 UTC, Jonathan M Davis wrote:
> On Tuesday, April 01, 2014 03:54:07 Jonathan M Davis wrote:
>> On Tuesday, April 01, 2014 05:35:28 ed wrote:
>> > OK, lazy me just read the std.satetime article again. It appears
>> > the design is for no invalid values and it is currently a known
>> > limitation due to CTFE.
>> > 
>> > ---
>> > d_time_nan	There is no equivalent. SysTime.init, which has a null
>> > TimeZone object, would be the closest, but once CTFE advances to
>> > the point that you can new up class objects with it,
>> > SysTime.init's timezone will be LocalTime, so don't rely on
>> > SysTime.init being invalid. std.datetime in general tries to
>> > avoid having any invalid states for any of its types. It's
>> > intended that creating such values be impossible.
>> > ---
>> > 
>> > I would still like to know if there is a way around this so I can
>> > have my struct default init.
>> 
>> You can certainly have a struct with a SysTime member, but there's no way
>> for it to use that SysTime without first assigning a valid value to it - at
>> least, not without segfaulting when it tries to use the SysTime in any
>> context which it would use its timezone member.
>> 
>> If you really want to have the SysTime be useable in the init value of your
>> struct, then you can make it so that each of its member functions which use
>> the SysTime member check it for validity first (or have a separate bool
>> which indicates whether the SysTime has been assigned to or not), in which
>> case, it could assign something like SysTime(0) to it, which would be the
>> valid equivalent of SysTime.init.
>> 
>> Unfortunately, that does add extra overhead, but there isn't any way around
>> it if you want to have the SysTime be used without having the user of the
>> struct assign to it first. It's pretty much the same boat that SysTime
>> itself is in. I could make it so that it checks the timezone for null every
>> time it's used and assign LocalTime to it if it's null, but that adds
>> constant overhead. My decision was that it was better to just live with the
>> fact that SysTime.init is invalid. It's debatable though, as it's a
>> trade-off.
>
> Actually, after thinking about this more after someone opened a bug on the
> fact that SysTime.init.toString() segfaults (since the timezone is null)
>
> https://d.puremagic.com/issues/show_bug.cgi?id=12507
>
> I think that I have a solution. It's now possible to default-intialize the
> timezonet to UTC so that SysTime.init is equivalent to SysTime(0, UTC()). It's
> not ideal, because it's not SysTime(0, LocalTime()), and SysTime normally
> defaults to LocalTime, but it will never be possible to default-initialize it
> to LocalTime thanks to the fact that it has to call tzset when it's
> initialized.
>
> You can look my comments in the bug for more details. I've opened a pull
> request with those changes, so the next release will probably have a valid
> SysTime.init, even if it's not SysTime(0, LocalTime()) like would be ideal.
>
> - Jonathan M Davis

I'll gladly switch to a default SysTime in the next release :)

I'm finding std.datetime very easy to use and overall a great API. Nice work!

Cheers,
ed