Skip to main content

Announcing Jactl 2.4.0

· 3 min read
James Crawford
Jactl Creator

Jactl 2.4.0 is a new release with enhancements and bug fixes.

This release provides new date/time classes and also adds the ability to extend the language with new built-in types.

Enhancements

#95 Ability to add new built-in types

This enhancement makes it possible for applications embedding Jactl to provided their own classes to be used as built-in types within the Jactl scripts and classes, adding to the existing list of built-in types such as List, Map, String, etc.

For example, consider this Point class:

package app.jactl;

public class Point {
public double x, y;
Point(double x, double y) { this.x = x; this.y = y; }
public static Point of(double x, double y) { return new Point(x,y); }
public double distanceTo(Point other) {
return Math.sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y));
}
}

To register it as a new built-in type called Point we just need to do this:

JactlType pointType = Jactl.createClass("jactl.draw.Point")
.javaClass(app.jactl.Point.class)
.autoImport(true)
.method("of", "of", "x", double.class, "y", double.class)
.method("distanceTo", "distanceTo", "other", Point.class)
.register();

Then, this type can be used by Jactl scripts:

Point p = Point.of(1,2)
p.distanceTo(Point.of(3,4)) // result: 2.8284271247461903

See Adding New Built-In Types for more details.

#96 New date/time built-in types

The ability to add new built-in types was used to provide new date/time classes as built-in types in Jactl by exposing the existing java.time.* classes.

The following Jactl classes now exist as built-in types in Jactl:

  • jactl.time.LocalTime
  • jactl.time.LocalDate
  • jactl.time.LocalDateTime
  • jactl.time.ZonedDateTime
  • jactl.time.Instant
  • jactl.time.Period
  • jactl.time.Duration
  • jactl.time.ZoneId

Examples:

// Creating instances — use parse(), of(), or now():
LocalTime t = LocalTime.parse('10:11:12.123456789')
LocalDate d = LocalDate.of(2026, 2, 26)
LocalDateTime dt = LocalDateTime.now()
ZonedDateTime zdt = ZonedDateTime.parse('2026-02-26T10:11:12+00:00[UTC]')
Instant i = Instant.ofEpochMilli(1772100672123L)

// Manipulating values — methods return new instances:
d.plusDays(5).plusMonths(3) // 2026-06-03
dt.minusWeeks(2) // 2026-02-15T15:00:36.536
zdt.withYear(1969) // 1969-02-26T10:11:12Z[UTC]
t.truncatedToMillis() // 10:11:12.123

// Formatting and querying:
d.format('yyyy MMM dd') // 2026 Feb 26
dt.getDayOfWeek() // 'SUNDAY'
d.isLeapYear() // false
i.getEpochSecond() // 1772100672

// Duration and Period for arithmetic:
Period p = Period.of(1, 2, 3) // P1Y2M3D
d.minus(Period.ofDays(27)) // 2026-01-30
Duration.between(dt, zdt) // PT-76H-49M-24.536S
t.until(t.plusHours(1)) == Duration.ofHours(1) // true

// Converting between types:
d.atTime(LocalTime.parse('10:11:12')) // LocalDateTime
dt.atZone(ZoneId.of('UTC')) // ZonedDateTime
zdt.toLocalDate() // LocalDate
t.atDate(d) // LocalDateTime

See Date/Type Types for more details.

Bug Fixes for 2.4.0

  • #92 Infinite loop during parsing if parameter list for function declaration has syntax error and begins with a comma
  • #93 Bug in equality check between maps that have non-string keys