owned this note
owned this note
Published
Linked with GitHub
# VSL Spec
### Workings
VSL is a language which compiles to LLVM and attempts to create near-metal code while maintaing a high-level syntax and semantics. For this reason VSL is designed to work nicely with C.
## Types
VSL has a couple **internal** types for all items:
- Functions
- Aliases (i.e. objects). Anything that refers to something in memory is an alias
- Types (i.e. classes, interfaces)
- Metaclasses (stores reflection data on types)
## Primitives vs Objects
Unlike Java or even C, VSL does not distinguish between objects and primitives. They act the exact same however at the compiler level, primitives are compiled to zero-overhead items (same as they would if you were in C).
For "primitives" their compilation is handled by the compiler but their definition is in `libvsl`.
### Default Data Type
- Integers `123` (8, 16, 32, 64 bit versions of each) (also unsigned versions of each) (arbitrary precision will also be supported)
- Decimals `123.456` (float & double)
- Strings `"foo"` (UTF-8 by default)
- Arrays `[1, 2, 3]`
- Dictionaries `[a: 1, b: 2, c: 3]`
- Tuples `("foo", 1)`
- Sets `{1, 2, 3}`
#### Type Details
- Default Integer (`Int` and `UInt`) are 32-bit.
- Root class is `Object`
- `Object` or types will _never_ have any pre-defined/inherited fields/methods
- STL should be bootstrapped, I should be able to write my own STL
- Tuple will be compiled to `vsl.Tuple$T1,T2`
- Hash buckets are pre-def at 8 and doubled each iter.
Some inheritance graphs:
```
Number<T>
|
+----------+----------+
| |
Integer<T> FloatingPoint<T>
| |
+-------+-------+-------+---------+---+ +-----+-----+
| | | | | | |
Int8 Int16 Int Int64 UnsignedInteger Double Float
(Char) (Int32) |
(Byte) +-------+---+---+-------+
| | | |
UInt8 UInt16 UInt UInt64
(UInt32) (CSize*)
(CSize*)
```
* CSize will be either depending on arch
## Strings
Strings are stored as a series of bytes (equiv. of C's `char*`), and a length. However anytime you interact with a string all operations are done through a class implementing the `StringView` interface which defines the encoding. The string class is defined as:
```swift
public class String<T: StringView = UTF8View>
```
The `= UTF8View` means the default generic is UTF8
halo new paragraph here
## Functions
Functions in VSL are like most other languages but VSL places an emphasis on _named parameters_. This helps functions like:
```java
req(80, "http://example.com", 500)
```
becomes:
```swift
request(port: 80, domain: "http://example.com", timeout: 500)
```
Funtions in VSL:
- can have optional args
- be overloaded based on type _and_ named parameters
- have default values for parameters.
### Examples
I can have both:
```swift
func set(followers: Int) { ... }
func set(posts: Int) { ... }
```
(this is a bad example tho because you should be ussing setters (described later))
Both functions are different from each other and can be both defined at once.
---
Another example
```swift
func request(to url: URL, timeout: Int = 500) -> String { ... }
```
## Classes/Structs/Interfaces
Interfaces can extend other interfaces and can provide default implementations for functions (and also getters/setters read later on that).
Structs are different from classes, structs are basically classes that basically only need to store some fields, they are passed by-value and have a default constructor:
```javascript
struct StoreItem {
let price: Int
let name: String
let description: String
let salePrice: Int?
}
```
now I can do:
```javascript
let foo = StoreItem(
price: 500,
name: "Goat",
description: "An actual goat"
)
```
If you're wondering about `salePrice: Int?`, read on about optionals
---
Classes support generics, extension, and inheritance.
example class:
```swift
class MyClass {
// ...
}
```
I can make a generic class using:
```swift
class MyClass<T> { ... }
```
or if I want to ensure the generic extends a class:
```swift
class MyClass<T: U> { ... }
```
### Inheritance
I can specify inheritance for both interfaces and classes such as:
```swift
class MyClass: ParentClass { ... }
interface Goatable: Animalable { ... }
```
I can implement an interface using:
```swift
class Downgoat: Goatable { ... }
```
Classes can inherit 1 class but as many interfaces as you want.
Interfaces can inherit as many interfaces as they want.
## Getters/Setters
We've all seen CS teacher say to do:
```java
public class BankAccount {
private let balance: Int
public func getBalance() -> Int {
return self.balance
}
public func setBalance(to value: Int) {
self.balance = value
}
}
```
Why? because if I want to update something else I could do:
```java
public func setBalance(to value: Int) {
display.update(balance: self.balance)
self.balance = balance
}
```
but in VSL you can just do:
```swift
public class BankAccount {
public let balance: Int {
didSet {
display.update(balance: self.balance)
}
}
}
```
Note: Internally getters/setters are converted to functions so this is why you can specify the value of a getter/setter in an interface but not a regular field.
## Optional
This is a big part. Rather than having `null` and `NullPointerException`s and all these surprises and requiring `== null` checks etc. (cough java). VSL makes it so you need to explictly define if a variable is ever `nil`, e.g.:
```
let a: Int = 1 // Never nil
let a: Int? = 1 // This can be nil (called an 'optional')
```
Additionally you cannot use use a variable that is an "optional" like a normal one, you _must_ unwrap it or specify some behavior for using it. Usually one might do this:
```
var animal: Animal? = ...
animal?.speak()
```
this uses the `?.` operator which will result in the expression evaluating to `nil` if `animal` is nil. That way `speak` is only called if `animal` is a non-null value.
Here are some ways to unwrap:
```
var x: T? = ...
if let a = x {
// a is unwrapped
} else {
// ono x is nil
}
// or...
let foo = x! // This will throw a runtime error if x is nil
// the above is not 100% garunteed to be in the spec yet
```
## More syntax
```swift
let array: Int[] = [1, 2, 3]
let tuple: (Int, Int, Int) = (1, 2, 3)
let dictionay: [String: Int] = ["A": 1]
let set = {1, 2, 3} // type signature for set not confirmed yet
```
Additionally `a..b` does range `[a, b)` and `a...b` does range `[a, b]`.
Iteration is:
```swift
for i in iterable {
...
}
```
We might use generators or maybe an interface for a class to be able to be used in a loop like this
---
The `?` can be used to create a lambda e.g.:
```
[1,2,3].map(? + 1)
```
## Syntax still under development
The syntax is still quite changing for these:
---
named tuples:
```swift
let downgoat = (size: 10, goatness: 100)
```
lambda:
```swift
let lambda = (args) => body
```
closure:
```swift
let closure = { 1 + 1 }
```
closures can be used at the end of functions:
```swift
a.map({1 + 1}) // or....
a.map { 1 + 1 }
```