We are announcing a new Crystal release 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.
Stats
This release includes 178 changes since 1.10.1 by 28 contributors. We thank all the contributors for all the effort put into improving the language! ❤️
Changes
Below we list the most remarkable changes in the language, compiler and stdlib. This is a pretty big release with lots of things going on, so hold tight 🚀
For details, visit the full changelog.
LLVM 18
One of the biggest steps forward is support for upcoming LLVM 18 which allows linking LLVM dynamically on Windows (#14101).
Additionally, LLVM 18 now provides everything we need in the upstream C API, removing the need for our wrapper extension llvm_ext
. It’s still necessary for older LLVM versions, so we’ll keep it around for a while. But the future tool chain is getting simplified. Read more in #13946.
Thanks @HertzDevil
Compiler Optimization Levels
The compiler gains four distinct optimization levels:
-O0
: No optimization-O1
: Low optimization-O2
: Middle optimization-O3
: High optimization
Each level activates the respective LLVM RunPasses
and CodeGenOptLevel
optimizations.
-O3
corresponds to the existing release mode and -O0
corresponds to the default non-release mode. -O0
remains the default and --release
is equivalent to -O3 --single-module
.
Effectively, this introduces two optimization choices between the previous full or nothing. And it’s now possible to use high optimization without --single-module
.
Read more in #13464.
Thanks @kostya
Alignment primitives
The language has two new reflection primitives: alignof
and instance_alignof
return a type’s memory alignment (#14087). This allows implementing type-aware allocators in native Crystal with properly aligned pointers.
They are siblings of sizeof
and instance_sizeof
and can be used in the same way.
class Foo
def initialize(@x : Int8, @y : Int64, @z : Int16)
end
end
Foo.new(1, 2, 3)
instance_alignof(Foo) # => 8
Effect on existing code
The introduction of these primitives makes it impossible to define methods of the same names. So def alignof
or def instance_alignof
are now invalid syntax.
We don’t expect there to be a big impact in practice.
Thanks @HertzDevil
dll
parameter in Link
annotation
The Link
annotation has a new parameter dll
for specifying dynamic link libraries on Windows (#14131).
@[Link(dll: "foo.dll")]
lib LibFoo
end
Thanks @HertzDevil
Macro @caller
context
Macros now have a reference to their calling context via the special instance variable @caller
(#14055).
macro foo
{{ @caller.line_number }}
end
foo # => 5
Thanks @Blacksmoke16
New collection methods
Enumerable#present?
is a direct inversion of #empty?
avoiding some quirks with the similar, but not-quite, #any?
(#13847).
Thanks @straight-shoota
Enumerable#each_step
and Iterable#each_step
are direct methods for creating step iterators (#13610).
Thanks @baseballlover723
Enumerable(T)#to_set(& : T -> U) : Set(U) forall U
and #to_a(& : T -> U) forall U
allow materialising an Enumerable
into a pre-defined collection, which gives more flexibility than the standard #to_set
and #to_a
methods (#12654, #12653).
Thanks @caspiano
Numeric enhancements
BigFloat#**
now works for all Int::Primitive
arguments and supports the full exponent range for BitInt
arguments (#13971, #13881)
Floating point to string conversion in printf
uses the Ryu algorithm (#8441).
New methods Float::Primitive.to_hexfloat
, .parse_hexfloat
, and .parse_hexfloat?
allow conversion to and from the hexfloat format (#14027).
More math features:
Math.fma
(#13934)Number#integer?
(#13936)Int32#abs_unsigned
,#neg_signed
(#13938)Int::Primitive#to_signed
,#to_signed!
,#to_unsigned
,#to_unsigned!
(#13960)
Thanks @HertzDevil
Enhancements for crystal spec
crystal spec
gets two new commands for introspection:
crystal spec --dry-run
prints all active specs without actually executing any spec code (#13804).
Thanks @nobodywasishere
crystal spec --list-tags
lists all tags defined in the spec suite (#13616).
Thanks @baseballlover723
Enhancements for crystal tool unreachable
The basic implementation of crystal tool unreachable
from Crystal 1.10 gets some useful enhancements.
- The
--tallies
option prints all methods and the total number of calls. Those with a zero tally are unreachable (#13969). - The
--check
flag exits with a failure status if there is any unreachable code (#13930). - Annotations show up in the output (#13927).
- New output format: CSV (#13926).
- Paths in the output are relativized, making it more succinct (#13929).
Thanks @straight-shoota
Inherited macros in API docs
Inherited macros are now exposed in the API docs. They had previously been hidden, in contrast to inherited defs (#13810).
Thanks @Blacksmoke16
Text
Regex::MatchData#to_s
returns the matched substring (#14115). Thanks @Vendicated- The new
EOL
constant (End-Of-Line) is a portable reference to the system-specific new line character sequence (#11303). Thanks @postmodern - We got new version-specific constructors for
UUID
:.v1
,.v2
,.v3
,.v4
, and.v5
(#13693). Thanks @threez StringScanner
now supportsString
andChar
patterns (#13806). Thanks @funny-falconChar::Reader
got some nilable character accessors:#current_char?
,#next_char?
,#previous_char?
(#14012). Thanks @HertzDevilString#matches_full?
is a simple API when you need a regular expression to match the entire string (#13968). Thanks @straight-shoota
Misc
- The capacity of
String::Buffer
andIO::Memory
was unintentionally limited to 1GB. They now support the full range up toInt32::MAX
, i.e. 2GB (#13989). Thanks @straight-shoota - There was a nasty bug in
Number#format
which could mess with the integral part. It is now fixed in #14061. Thanks @HertzDevil - Vendored shards
markd
andreply
are no longer referenced by paths relative to the compiler source tree. This means they can be local dependencies (i.e. inlib
) when using the compiler as a library (#13992). Thanks @nobodywasishere - There are two new constants which provide information on the compiler host and target:
Crystal::HOST_TRIPLE
andTARGET_TRIPLE
(#13823). Thanks @HertzDevil
Shards 0.17.4
The bundled shards release was updated to 0.17.4 which brings a couple minor bugfixes. (#14133).
Thanks @straight-shoota
Experimental: ReferenceStorage
and .pre_initialize
We’ve started an effort to make it easier to use custom allocation mechanisms in Crystal and decouple allocation from initialization.
The main tool is Reference.pre_initialize
which performs the rudimentary object initialization, before actually calling #initialize
.
Reference.unsafe_construct
is a higher level API on top of that.
ReferenceStorage
represents a static buffer for a reference allocation.
These APIs are experimental and might be subject to change. We expect more features in this direction in future releases. Join the discussion about custom reference allocation at #13481.
NOTE:
ReferenceStorage
was removed again in 1.11.1 due to compatibility issues with older versions of the standard library (#14207). It will come back with an improved implementation.
Thanks @HertzDevil
Deprecations
- Splat operators in macro expressions are deprecated. Use
.splat
instead (#13939) LLVM.start_multithreaded
and.stop_multithreaded
. They have no effect (#13949)LLVMExtSetCurrentDebugLocation
fromllvm_ext.cc
for LLVM 9+ (#13965)Char::Reader#@end
(#13920)
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!