Skip to content
GitHub Repository Forum RSS-Newsfeed

Crystal 1.19.0 is released!

Julien Portalier

We are announcing a new Crystal release 1.19.0 with several new features and bug fixes.

Pre-built packages are available on GitHub Releases and our official distribution channels. See crystal-lang.org/install for installation instructions.

This release includes 237 changes since 1.18.2 by 24 contributors. We thank all the contributors for all the effort put into improving the language! ❤️

Below we list the most remarkable changes in the language, compiler and stdlib. For more details, visit the full changelog.

We do not expect any breaking changes in existing code. If you notice any unexpected issues, please let us know in the issue tracker or forum.

The following changes break prior behavior of the compiler, but we expect them to not have much effect in existing code. If you notice any unexpected issues, please let us know in the issue tracker or forum.

The flag? macro is now aware of name-value mappings in the form of name=value where flag?(:name) will now return the respective value as a StringLiteral (#16310). A key without a value returns true as implicit value, as before.

Instead of returning a BoolLiteral the flag? macro might now return a StringLiteral which might be unexpected. The value is still truthy and shouldn’t cause issues in practice.

For example, the value printed by `` may now be:

  • (not defined) => false
  • -Dname => true
  • -Dname=value => "value"
  • -Dname=some,other,data => "some,other,data"

Thanks, @straight-shoota

The monotonic clock has been adjusted on Linux and macOS to include suspended time, when they previously counted the system uptime.

UNIX targets still use CLOCK_MONOTONIC except for Linux that now uses CLOCK_BOOTTIME (#16516) and macOS that now uses CLOCK_MONOTONIC_RAW instead of mach_absolute_time that internally used CLOCK_UPTIME_RAW (#16516, #16492).

The change is affecting Time.measure for example, that should now include suspended time across the different targets, rather than sometimes including it, and sometimes not.

Execution contexts from RFC 0002 continue as a final preview feature with opt-in with compiler flags -Dpreview_mt -Dexecution_context and we plan to finally enable the feature by default in the 1.20 release!

There has not been huge developments to the feature, but corrections to fix the remaining thread safety issues in the standard library, for example:

  • Add thread safety to default random (#16174)
  • Closing system fd is thread unsafe (#16289)
  • Thread safety of Exception::Callstack (#16504)

We started to merge synchronization primitives from ysbaddaden/sync into the standard library as well:

This effort is part of the ongoing project to improve multi-threading support with the help of 84codes.

Thanks, @ysbaddaden

Introduces the Time::Instant type to represent instants on the monotonic timeline as defined in RFC 0015 instead of overloading the Time::Span type that represents a duration, not an instant (#16490). We expect a clearer and safer API:

  • Time::Instant represents a single point on the monotonic timeline.
  • Time::Span continues to represent a duration.
  • Subtracting two Time::Instant instances yields a Time::Span.
  • Adding/subtracting a Time::Span to/from an Time::Instant yields a new Time::Instant.

We also adjusted the monotonic clock (#16516), applied the changes (#16498) and deprecated Time.monotonic (#16545).

For example:

timeout = 5.seconds
start = Time.instant

while start.elapsed < timeout
  # do something
end

In order to migrate existing code to Time::Instant, replace calls to Time.monotonic with Time.instant. If the instant time reading is stored in an explicitly typed variable (e.g. an instance variable), change the type from Time::Span to Time::Instant. The APIs of these types are very similar so most use cases should not need any further adaptions.

Finally, we made some further adjustments:

  • Treat GMT as a legacy alias of UTC (#16292)
  • Add /etc/zoneinfo to zoneinfo lookup paths (#16463)
  • Add support for $TZDIR (#16466)

Thanks, @straight-shoota

A long refactor of spawning sub-processes has started. It encompasses a tedious cleanup and safety fixes related to finding the command as well as building the arguments and environment variables, to eventually move on from the classic fork then exec to the more modern posix_spawn on UNIX targets.

  • Create argv before fork (#16286, #16321)
  • Move make_envp before fork (#16351)
  • Use execvpe when available (#16294, #16311)
  • Replace Dir.cd with a non-raising alternative in pre-exec (#16352, #16369)
  • Fix reset directory if Process.exec fails (#16383)
  • Disable process cancellation during fork (#16446)

Thanks, @straight-shoota

New methods:

Enhancements:

  • Support large JSON files (#16211)
  • Support deserialization of YAML anchors of value types (#16186)
  • Add end locations to scalars and aliases in YAML::Nodes.parse (#16187)
  • Set JSON::SerializableError#attribute when appropriate (#16158)
  • Add remove_empty parameter to String#each_line (#16232)
  • Add weeks parameter to Time::Span.new (#16208)
  • Support 0X, 0O, 0B prefixes in string to integer conversion (#16226)

Thanks, @andrykonchin, @carlhoerberg, @HertzDevil, @ysbaddaden, @straight-shoota, @RX14, @Sija, @spuun

The memory management model for libxml2 changed in Crystal 1.17 to become manual instead of integrating the GC. The change introduced some memory leaks that have now been fixed.

  • Memory leak in XML.parse and XML.parse_html methods (#16414)
  • Memory leak in XML::Document#finalize (#16418)
  • Memory leak in XML::Node#content= (#16419)
  • Fix use after unlink in XML::Node (#16432)

Thanks, @toddsundsted

New methods:

Thanks, @Blacksmoke16, @HertzDevil

  • All overloads of ArrayLiteral#[] return nil on out of bounds (#16453)

Thanks, @HertzDevil

The compiler is now always built with execution contexts, and the LLVM codegen is now always multithreaded for every target, including Windows. We can finally wave goodbye to fork, and Windows should see a performance boost.

Tools:

Thanks [@nobodywasishere], @straight-shoota

We finally build Linux ARM64 binaries of Crystal releases and nightlies. Tarballs are ready to download from github releases, docker images, snapcraft or the install-crystal github action.

  • Build linux aarch64 tarballs (#16330)
  • Build snap arm64 target (#16491)
  • Enable multiarch docker builds (#16493)
  • Encourage +1 reactions on issues and PRs for prioritization (#16241)

Thanks @straight-shoota, @ysbaddaden

The OpenSSL bindings now require OpenSSL 1.1.1+ or LibreSSL 3+. We expect the change to not have any effect since these versions are no longer distributed by any supported operating system.

Thanks @ysbaddaden

  • Deprecate single-letter macro fresh variables with indices (#16267)
  • Deprecate macro fresh variables with constant names (#16293)
  • Deprecate StringLiteral#split(ASTNode) (#16439)
  • Deprecate Time.monotonic (#16545)
  • Deprecate Time#inspect(io, *, with_nanoseconds) (#16416)

Thanks @HertzDevil, @straight-shoota


Thanks

We have been able to do all of this thanks to the continued support of 84codes and every other sponsor. To maintain and increase the development pace, donations and sponsorships are essential. OpenCollective is available for that.

Reach out to crystal@manas.tech if you’d like to become a direct sponsor or find other ways to support Crystal. We thank you in advance!

Contribute