3.5 KiB
3.5 KiB
design choices
- no macros, try to keep parsing fast. instead, have constant time expressions
- static typing in a scripting language, but may need to be able to make ad-hoc structs
- push work to the definition instead of making callers handle stuff (ie
Drop
will exist,defer
won't)
typing?
// rust style
struct Foo<T> {
param: T,
}
// zig style
fn Foo(T: type) -> type {
struct {
param: T
}
}
// how would traits work with zig style stuff?
// rust style
fn length<T>(vec: Vec<T>) -> u32 { }
// zig style
fn length(vec: ???) -> u32 { ??? }
fn main() {
let a: Foo<i32> = Foo {
foo: 10,
};
let b: Foo(i32) = Foo(i32) {
};
}
packages?
// rust-style "use"
// can be used to bring anything in scope, not only packages
use foobar;
use foobar::{a, b, c};
// typescripty imports
// strings make it easier to import
import "foobar" as name;
import "foobar" as { a, b, c };
import "https://foobar.tld/path/to/file" as name;
// import "foobar"; // bad?
// use with urls?
use "https://foobar.tld/path/to/file" as name;
use "https://foobar.tld/path/to/file"::Client;
// imports as functions
// feels strange if import is a function but export/pub is a keyword
// but it also is more extensible import(something, ...argv)
let foobar = import("foobar");
let { a, b, c } = import("foobar");
context?
trait Entry {
fn is_dir(self) -> bool;
fn is_file(self) -> bool;
fn is_symlink(self) -> bool;
fn name(self);
fn create(self);
fn open(self);
fn remove(self);
fn rename(self);
fn truncate(self, size: u64);
fn exists(self);
fn metadata(self) -> Metadata;
}
trait File is Read + Write + Seek + Entry {}
struct Metadata {
ino: u64,
len: u64,
modified: u64,
permissions: Permissions,
}
trait Filesystem {
fn entry(self, path: Path) -> Entry;
fn open(self, path: Path, options: OpenOptions) -> File {
self.entry(path).open(options)
}
fn read<T>(self, path: Path) -> T {
// bikeshedding go brrr
self.open(path, .Read).read();
// "infer struct type"
foo(path, .{});
foo(path, :{});
// maybe ditch {} and go for []?
// but then what would be for arrays?
foo(path, [foo: bar]);
foo(path, [foo = bar]);
foo(path, StructType { foo: bar });
foo(path, StructType { foo = bar });
foo(path, StructType [ foo: bar ]);
foo(path, StructType [ foo = bar ]);
self.open(path, :Read).read()
}
fn write(self, path: Path, data: View<[u8]>) -> Result<(), Error> {
self.open(path, :Write).write(data)
}
}
// vars, cli args, current directory/file, etc
struct Environment { ... }
trait Network {
fn listen_tcp(self, addr: SocketAddr) -> Result<TcpServer, Error>;
fn connect_tcp(self, addr: SocketAddr) -> Result<TcpClient, Error>;
fn listen_tls(self, addr: SocketAddr) -> Result<TlsServer, Error>;
fn connect_tls(self, addr: SocketAddr) -> Result<TlsClient, Error>;
fn bind_udp(self, addr: SocketAddr) -> Result<UdpSocket, Error>;
}
// all context is passed into
struct Context {
fs: Filesystem,
env: Environment,
os: Os,
net: Network,
log: Log,
}
// fn main({ log }: Context) {
fn main(ctx: Context) {
// do things with ctx here...
ctx.log.info("hello world!");
let http = HttpClient::new(ctx.net);
http.get("https://url.tld/path/to/something").send()?.json()?;
http.post("https://url.tld/path/to/something").body(something)?;
}
// problem: i'd need to pass ctx to *every* function that wants to log?
fn another() {
// maybe this?
import { log } from "context";
log.debug("something");
}