6.10.94-stable
In this page
  1. 7.0
  2. 6.10
  3. 5.x to 6.x

Core Changelog

7.0

Precision Decorator

Float values can now be decorated by an annotation @precision(0.01). The annotation value defined the expected precision kept by GreyCat by the dev. This simple annotation can compress by an order of magnitude the size of GreyCat store.

Private type attribute

Keyword private is now available to protect type attributes from external mutations. The following example illustrates the semantics associated to the keyword.

Essentially, only local methods are allowed to mutate private attributes.

use util;

type Foo {
  private x: int;

  fn set(x: int) {
    this.x = x; // correct
  }
}

fn main() {
  var foo = Foo { x: 5 };
  foo.set(100);
  Assert::equals(foo.x, 100); // allowed to read private attribute

  foo.x = 42; // this will raise an error
}

New command: install

A new command install is available in the greycat CLI

This command will download the required libraries defined in the project.gcl:

@library("basic_c", "7.0.14-dev");

Before the first greycat run (or serve), user should run:

greycat install

It should output something like:

Download: https://get.greycat.io/files/lib/basic_c/dev/7.0/arm64-apple/7.0.14-dev.zip
	Success
	Extracted: /Users/duke/.greycat/lib/basic_c/7.0.14-dev/basic.gcl
	Extracted: /Users/duke/.greycat/lib/basic_c/7.0.14-dev/basic_c.gclib

New command: print

A new command print is available in the greycat CLI

This command prints to stdout the content of the given GreyCat binary file (.gcb)

greycat print result.gcb

A --format=json flag can be specified to have it output JSON instead:

greycat print --format=json result.gcb

Removed module: math

Module math as been removed from the std library.

All math functions are now directly accessible from the core module.

The core module being always available in scope, it does not require any additional use statement now to use the old math symbols.

Updated types: Date, time

Date is no longer a native type, it is now designed for human presentation, while time is designed for calculations.
This means that most of the v6 Date API has been moved to time.

API Breaking changes

v6 v7
Date::new(): Date Date {year: , month: , ...} normal object creation
Date::fromEpoch(): Date Date::fromTime(time, TimeZone)
Date::toTime(): time Date::toTime(TimeZone): time
Date::add() removed, time::calendar_add(value, CalendarUnit, TimeZone)
Date::substract() removed, time::calendar_add(value, CalendarUnit, TimeZone) negative value
Date::floor() removed, time::calendar_floor(CalendarUnit, TimeZone): time
Date::ceiling() removed, time::calendar_ceiling(CalendarUnit, TimeZone): time
Date::startOfWeek() removed, time::startOfWeek(TimeZone): time
Date::dayOfYear() removed, time::dayOfYear(TimeZone)
Date::dayOfWeek() removed, time::dayOfWeek(TimeZone)
Date::weekOfYear() removed, time::weekOfYear()
Date::leapYear() removed
Date::isLeap() removed, time::isLeap(year: int)
Date::daysInYear() removed
Date::daysInMonth() removed
Date::totalDaysInYear() removed, use time::totalDaysInYear(year)
Date::totalDaysInMonth() removed, use time::totalDaysInMonth(month, year)
Date::startOfWeek() removed, use time::startOfWeek(Timezone):time
Date::endOfWeek() removed, use time::endOfWeek(Timezone):time
Date::set() removed, either set field, or use time methods (safer)
Date::setTimeZone() removed, timezone is not stored
Date::getTimeZone() removed, timezone is not stored
Date::shiftTimeZone() removed, timezone is not stored
Date::clone() removed
Date::toString() removed
Date::get(DatePart::year),… removed, use Date.year, Date.month, etc.
Date::year(), … removed, use Date.year, Date.month, etc.
Date::diff() removed, use an operation eg. date1.year - date2.year, or use times
Date::equals() removed, use an operation eg. date1.year == date2.year, or use times
Date::min(), max() removed, use time:min(), time::max()
time::toDate(): Date removed, Date::fromTime(time, TimeZone): Date
time::toDateUTC(): Date removed, Date::fromTime(time, TimeZone): Date

The new CalendarUnit replaces DatePart:

enum CalendarUnit {
  year(0);
  month(1);
  day(2);
  hour(3);
  minute(4);
  second(5);
  microsecond(6);
}

Updated type: Quantizer

Quantizer is no longer a native type, its configuration is set at object creation.

The configuration per dimension is set with the appropriate type: QuantizerSparseDim and QuantizerDenseDim. Their use is unchanged from v6.

API Breaking changes

v6 v7
Quantizer::configure(dim: Array<any>): Quantizer see below
Quantizer::new(): Quantizer Quantizer {dimensions: Array<QuantizerDim>} normal object creation
Quantizer::dimensions(): int removed, available from dimensions field

6.10

  • migrate mbedtls to 3.6.0
  • add support for Google OAuth2 SSO
  • add protection and raise error for modification of nodeX while iterating over it
  • add support for Key rotation of SSO such as Azure AD
  • add support for Linux AArch64 platform and glibc binaries
  • add executable signature for Apple related binaries
  • add executable signature for Windows related binaries
  • add skeleton for Apple .app
  • cleanup STD GCL files according to newly introduced LSP server with better nullable checkes
  • enable support for weakly formed CSV with nullable empty fields
  • fix http get support for server that do not add binary len property
  • fix ABi protocol for broken Array message
  • fix codegen for SDK Java to allows unaligned version of ABI server and generated code
  • fix support for breaking statement within for-in loops
  • fix rangeSize in nodeTime and nodeList
  • fix CSV support for trailing null values

5.x to 6.x

  • Installation Install GreyCat v6 by visiting here, then:
  • Rename: ~/.greycat/licence to ~/.greycat/license (notice that ‘c’ becomes ‘s’)

API breaking changes

v5 v6
Env::get System::getEnv()
Table::new(2, true) Table::new(2)
Table<T>::new(8, true) Table<T>::new(8)
CSVColumnString CsvColumnString
CSVColumnFloat CsvColumnFloat
CSVColumnInteger CsvColumnInteger
CSVColumnTime CsvColumnTime
CSVColumn CsvColumn
CSVFormat::new() CsvFormat {}
CSVFormat CsvFormat
BoxPlotF64 BoxPlotFloat
PCA::new() PCA {}
GaussianND::new() GaussianND {}
Tensor::new() Tensor {}
Gaussian::new() Gaussian {}
HistogramF64::new() HistogramFloat {}
HistogramI64::new() HistogramInt {}
gaussian.min() gaussian.min
ProgressTracker::new(); p.start(); ProgressTracker { start: time::now() };
p.steps() p.counter
p.throughput() * 1000000 p.speed (speed now is counter / s before it was counter / us)
p.duration() p.duration
.bin extension renamed to .gcb
@library("network"); no longer needed, lib network has been merged in std::io
Directory::new File::mkdir
Directory::open FileWalker::new
FileWriter::new("${filename}.json", false) JsonWriter::new("${filename}.json")
FileWriter::new("${filename}.bin", false) GcbWriter::new("${filename}.gcb")
fw.writeBin(metaTypeIndex) fw.write(metaTypeIndex);
File::open has different semantic now, it returns a file descriptor and not a reader. To read we need a specific type based on the format (eg. JsonReader, CsvReader, etc.)
File::open("${filename}.bin"); GcbReader::new("${filename}.gcb")
file.readBin() file.read()
file.close() file = null;
File::open(csvPath) csvFile = CsvReader::new(csvPath, csvFormat)
csvFile.read(csvFormat) csvFile.read() Ideally replace to csvFile.readTo(obj)
csvFile.name() doesn't exist anymore
csvFile.path() path
use http;, use smtp; use io;
JSON::parseFile(file) JsonReader::new(file.path).read()
gaussian.clear() gaussian = Gaussian{}
var clonedGaussian = gaussian.clone() var clonedGaussian = clone(gaussian)
Task::spawn("module.function", [params]); Task::spawn(module::function, [params]);
SmtpAuthMode SmtpAuth
SmtpConfig {...}; Smtp {...};
Smtp::send(...); var smtp = Smtp {...}; smtp.send(...);
Email {..., contentType: EmailContentType::html, ...} Email {..., body_is_html: true, ...}
@public @permission("public")
  • File iterator

    • Old v5 way:
    for (i, entry in dir) {
      if (entry is Directory) {
        // entry is dir
      } else if (entry is File) {
        // entry is file
      }
    }
    
    • New v6 way:
    var fw = FileWalker::new(path);
    if (fw != null) {
      while (!fw.isEmpty()) {
        var entry = fw.next();
        if (entry != null) {
          if (entry.isDir()) {
            // entry is dir
          } else {
            // entry is file
          }
        }
      }
    }
    
  • Update webpack proxy middleware

module.exports = (app) => {
    app.use(
        // ensures all non-GET requests are sent to GreyCat instead of Webpack-dev-server
        createProxyMiddleware((path, req) => req.method !== 'GET' || path.match('^/files'), {
            // your GreyCat endpoint URL
            target: greycatProxy,
        }),
    );
};
  • Get files (JavaScript) See source

  • Upload files (JavaScript) See source

  • Download files in the browser (JavaScript)

const link = document.createElement('a');
link.download = 'myFile.csv'; // the name of the downloaded file in the browser
link.href = '/files/path/to/myFile.csv'; // the actual path to download the file on GreyCat
document.body.appendChild(link);
link.click(); // triggers the download
document.body.removeChild(link);
  • Download file from task result
export const downloadResource = async (task: runtime.Task) => {
    fetch(`/files/${task.user_id}/tasks/${task.task_id}/result.gcb?json`)
        .then((res) => {
            return res.text();
        })
        .then((data) => {
            const fileName = data.trim();
            const link = document.createElement('a');
            link.download = fileName;
            const url = new URL(`/files/${task.user_id}/tasks/${task.task_id}/${fileName}`, window.location.origin);
            link.href = url.toString();
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        });
};
  • Task API
const task = await myModule.myTask();
const handler = new TaskHandler(task);
const info = await handler.start(pollingDelayInMs, (info) => {
    // if you want to show progress somewhere
});
// getting files is using the standard "files" API
const result = await greycat.default.getFile(`${task.user_id}/tasks/${task.task_id}/result.gcb`);
const args = await greycat.default.getFile(`${task.user_id}/tasks/${task.task_id}/arguments.gcb`);
  • New Enums

Get an Enum by accessor method:

<module>.<enum>.<enumAccessor>()

e.g.:

const role = tenant.TenantRole.superadmin();

Get an Enum by string:

<module>.<enum>[<string> as <module>.<enum>.Field]()

e.g.:

const field = "superadmin"
const role = tenant.TenantRole[field as tenant.TenantRole.Field]();

Compare Enums Just compare them directly, no need to use value nor field (now called key).

  • New concepts
  • File now is just the file descriptor (name, path, size etc)
  • For every specific format, there is dedicated class for example: JsonReader, CsvReader etc.
  • You can get specific file paths by calling these static methods:
    • File::baseDir() translates to "./gcdata/files/"
    • File::userDir() translates to "./gcdata/files/<user_id>/"
    • File::taskDir() translates to "./gcdata/files/<user_id>/tasks/<task_id>"

where <user_id> and <task_id> are contextual.

  • Code generation

    v5 v6
    greycat-lang gen -o ./src/greycat greycat codegen project.gcl ./src/greycat
  • Styling if using MUI

@import '@greycat/web/css/greycat.base.css';

else

@import '@greycat/web/css/greycat.css';
  • Breaking changes

Can not spawn Tasks from a spawned Task , only one level possible.

Progress tracker in Task is disabled

All usage of structuredClone need to be changed.