type system
Primitive & Objects
Ysharp is a dynamic typed language with support of optional type tags attributes. Type system works like Type Script but it checks type compatibility in runtime instead of compile time.
In Ysharp, every variable is NOT derived from object type. There are primitives and object types.
There are 5 primitive types in Ysharp
- int
- double
- char
- bool
- null
There are 3 object types in Ysharp
- function
- class
- string
Note
Strings are categorized under object but parser has built in support for creating strings so you can use shorthand for creating string just like primitive types. I believe using string as primitive is more natural to most of the programmers so i added this feature.For example :
var f_name = "yagiz"; // shorthand for creating string
var l_name = new String("erdem"); // explicit object syntax
println f_name + " " + l_name; // yagiz erdem
Under string section you can access full api documentation .
Naming Conventions
Always use the same coding conventions for all your Ysharp projects.
Coding conventions are style guidelines for programming. They typically cover:
- Naming and declaration rules for variables and functions.
- Rules for the use of white space, indentation, and comments.
- Programming practices and principles.
Coding conventions secure quality:
- Improve code readability
- Make code maintenance easier
Coding conventions can be documented rules for teams to follow, or just be your individual coding practice.
Always use the same naming convention for all your code. For example:
- Variable and function names written as camelCase
- Global variables written in UPPERCASE (We don't, but it's quite common)
- Constants (like PI) written in UPPERCASE
Underscores:
Many programmers prefer to use underscores (date_of_birth), especially in SQL databases.
Underscores are often used in PHP documentation.
PascalCase:
PascalCase is often preferred by C programmers.
camelCase:
camelCase is used by Ysharp itself.
Note
All characters in identifier must be alfa-numeric and identifier cannot start with numeric character .For example:
var 1a = 40; // Syntax error
var a1 = 40; // OK
var _a = 40; // OK variables can start with underscore
Primitives
In Ysharp, a primitive (primitive value, primitive data type) is data that is not an object and has no methods or properties. Most of the time, a primitive value is represented directly at the lowest level of the language implementation.
All primitives are immutable, they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned to a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered. The language does not offer utilities to mutate primitive values.
// int
var age = 21;
println age; // 21
// double
var pi = 3.14;
println pi; // 3.14
// char
var letter = 'A';
println letter; // A
// bool
var isActive = true;
println isActive; // true
// null
var data = null;
println data; // null
Objects
Objects are runtime structures that has prototype, instance/object level method/properties. Objects are specialized under 3 categories which are strings, functions, classes.
Functions & Classes
In Ysharp, functions and classes are categorized into subtypes based on how they are defined and used.
Function Types
Ysharp supports three types of functions:
-
User defined functions
Functions declared by the user using the function keyword. -
Lambda expressions
Anonymous functions that can be defined inline. They are similar to lambda (arrow) functions in JavaScript. -
Native functions
Built in functions provided by the Ysharp runtime and standard library.
Class Types
Ysharp supports two types of classes:
-
User defined classes
Classes created by the user using the class keyword. -
Native classes
Built in classes provided by the Ysharp runtime and standard library.
You can visit class, function and string api documentation to get more details, theese topics are very deep and i dont want to go over every single api in this section.
Type tags
Type tags adds syntax on top of Ysharp expressions, allowing developers to add types.
Unlike statically typed languages, Ysharp does not enforce types at compile time.
Instead, type tags are checked at runtime to ensure that assigned values are compatible.
Type tags are used to:
- Improve code readability
- Catch type errors early (at runtime)
- Document developer intent
- Add lightweight type safety without losing flexibility
Syntax
Type tags are declared after variable or parameter names:
var x : int = 10;
var name : string = "yagiz";
var flag : bool = true;
If no type is provided, default is any. Programmer do not have to write any. Any type matches with all value types .
var x : any = 10;
Supported Type Tags
Primitive Types
- int
- double
- number (accepts both int and double)
- char
- bool
Special Types
any → accepts all values function string
Custom Types
User defined class names can also be used:
class Person {}
var p : Person = new Person(); // OK
Runtime Type Checking
Type checking happens during assignment:
var x : int = 10;
x = 20; // OK
x = "text"; // ERROR
Null Behavior
null is allowed for all types:
var x : int = null; // OK
var name : string = null; // OK
Type Compatibility
var x : number = 10; // OK (int → number)
var y : number = 3.14; // OK (double → number)
var z : int = 3.14; // ERROR
Function Parameters
Type tags can be used in function parameters:
function add(a : int, b : int) do
return a + b;
end
add(10, 20); // OK
add(10, "x"); // ERROR
Return Types
function square(x : int) : int do
return x * x;
end
var a : int = square(4); // 16 OK
var b : string = square(4) // ERROR
// function cannot return string since it has int type taf for return
function test() : int do
return "string";
end
test();
Class Fields
Type tags can be used in class properties:
class User {
var name : string;
var age : int;
}
Type Tags vs Dynamic Typing
Ysharp remains fully dynamic, even with type tags:
- Types are optional
- Types are enforced only at runtime
- No compile time type system exists
Best Practices
- Use
anyonly when necessary - Prefer
numberoverint/doubleif flexibility is needed - Use type tags in public APIs (functions, classes)
- Avoid over typing internal temporary variables
Type Api
There is a separate api for making type checks and type conversions.
Type Class
Static Methods
| Method | Signature | Return Type | Description |
|---|---|---|---|
getType | Type.getType(value) | string | Returns the type name of the given value (e.g. "number", "string", "array") |
getTypeTag | Type.getTypeTag(value) | string | Returns the user-defined or environment-specific type tag associated with the given value |
isBool | isBool(value: any) | bool | Returns true if the given value is of type boolean |
isChar | isChar(value: any) | bool | Returns true if the given value is of type char |
isClass | isClass(value: any) | bool | Returns true if the given value is of type class |
isClassInstance | isClassInstance(value: any) | bool | Returns true if the given value is a class instance |
isDouble | isDouble(value: any) | bool | Returns true if the given value is of type double |
isFunction | isFunction(value: any) | bool | Returns true if the given value is a function or callable |
isInt | isInt(value: any) | bool | Returns true if the given value is of type integer |
isNativeObject | isNativeObject(value: any) | bool | Returns true if the given value is a native (Java-backed) object |
isString | isString(value: any) | bool | Returns true if the given value is of type string |
Static Class
| Class | Constructor Signature | Type | Description |
|---|---|---|---|
Type.Converter | no signature - static class | _Converter_ <class:Converter> | Converter class used for data conversions |
Converter Class
Static Methods
| Method | Signature | Return Type | Description |
|---|---|---|---|
| constructor | Type.Converter() | - | Static class, cannot be instantiated |
| toString | Type.Converter.toString(v : any) | string | Converts given value to string |
| toInt | Type.Converter.toInt(v : any) | int | Converts given value to integer |
| toDouble | Type.Converter.toDouble(v : any) | double | Converts given value to double |
| toChar | Type.Converter.toChar(v : any) | char | Converts given value to char |
| toBool | Type.Converter.toBool(v : any) | bool | Converts given value to boolean |
| toNativeObject | Type.Converter.toNativeObject(v : any) | any | Converts value to native (Java-backed) object |
Examples
var a = 10;
var b = 10.5;
var c = "hello";
var d = true;
println(Type.isInt(a)); // true
println(Type.isDouble(b)); // true
println(Type.isString(c)); // true
println(Type.isBool(d)); // true
class User {
var name;
constructor(name) do
this.name = name;
end
}
var u = new User("yağız");
println(Type.isClass(User)); // true
println(Type.isClassInstance(u)); // true
println(Type.isClassInstance(User)); // false
function add(a, b) do
return a + b;
end
var x = 5;
println(Type.isFunction(add)); // true
println(Type.isFunction(x)); // false
var a : number = 10;
println Type.getType(a); // int
println Type.getTypeTag(a); // number
var arr = [1, 2, 3];
println(Type.isNativeObject(arr.toNativeArray)); // true
println(Type.isNativeObject(Type.Converter.toNativeObject(arr))); // true
println(Type.isNativeObject(arr)); // true
var x = "123";
var n = Type.Converter.toInt(x);
println(n + 1); // 124
var d = Type.Converter.toDouble("3.14");
println(d * 2); // 6.28
var s = Type.Converter.toString(999);
println(s); // "999"
var x = "abc";
var n = Type.Converter.toInt(x); // throws error
function process(value) do
if Type.isInt(value) then do
return value * 2;
end
if Type.isString(value) then do
return value + "!";
end
return null;
end
println(process(10)); // 20
println(process("test")); // "test!"