Pre-release JETH is under active compiler and security review.
Language

Types

JETH is statically typed. Every value has a type known during compilation, and the type determines its valid operations, storage representation, ABI encoding, conversion rules, and default value.

This section is split into three detailed chapters:

  1. Value types covers integers, booleans, addresses, fixed bytes, enums, brands, and function references.
  2. Reference and composite types covers dynamic bytes/string, arrays, mappings, structs, nested composites, and tuples.
  3. Data locations and copying covers storage, calldata, memory, aliasing, deep copies, dynamic cleanup, and delete.

Type families#

FamilyJETH syntaxMain representation
Unsigned integeru8 through u256EVM word, checked arithmetic
Signed integeri8 through i256Two's-complement EVM word
BooleanboolStrict zero/one ABI word
Addressaddress160-bit value
Fixed bytesbytes1 through bytes32Left-aligned byte sequence
Dynamic bytesbytesDynamic ABI/storage/memory value
StringstringUTF-8 byte sequence
Enumenum Name { ... }uint8-backed nominal type
Brandtype X = Brand<Base>Erased nominal value type
Dynamic arrayT[]Location-dependent reference value
Fixed arrayArr<T, N>Inline or aggregate value
Mappingmapping<K, V>Storage-only hashed association
Structtype P = { ... }Ordered fields/ABI tuple
Tuple[A, B]Multiple values
Function referenceinferred/supported signatureInternal callable reference

No implicit dynamic typing#

There is no any, runtime union, implicit number/string conversion, truthiness, undefined, or null. Conversions must be permitted by the source and target types and are often explicit.

Worked type example#

This contract combines a nominal identifier, a struct, a dynamic array, a fixed-size array, and a storage mapping:

example.jeth
type UserId = Brand<u256>;

type Profile = {
  id: UserId;
  owner: address;
  scores: u256[];
  flags: Arr<bool, 2>;
};

class Profiles {
  owners: mapping<UserId, address>;

  register(id: UserId, owner: address): External<void> {
    require(owner != address(0n), "zero owner");
    this.owners[id] = owner;
  }

  get ownerOf(id: UserId): External<address> {
    return this.owners[id];
  }
}

UserId is represented as its u256 base in the ABI and EVM, but it remains a distinct source type. Profile is a tuple in the ABI. Its scores field makes the complete struct dynamically encoded. owners is storage-only and therefore cannot be an external parameter or return value.

Shape and location#

Two values with the same source type can use different runtime representations in storage, calldata, and memory. Compiler support is therefore sometimes consumer-specific. For example, returning a nested aggregate and copying it to storage are different operations with different safety requirements.

Continue with value types.