Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // "type" is an actual type in zig, that being said, here's your
- // generics, bro:
- fn GPoint(comptime measure: type) type {
- // Shit will be solved compile time unless it can't. This
- // means you can use the language as you'd use the C
- // preprocessor, for instance. In this case, at run time there
- // are no types, so all this bullshit is compile time only.
- // This is the target type for computations like len.
- comptime var tt = f32;
- if (measure == f64 or measure == f128)
- tt = measure;
- return struct {
- // @This() gives us this type's type :)
- const Self = @This();
- x: measure,
- y: measure,
- const center = Self{
- .x = @as(measure, 0),
- .y = @as(measure, 0)
- };
- // Inline functions are always inlined, it's not just a
- // suggestion
- fn len2(p2: GPoint(tt), p1: GPoint(tt))
- callconv(.Inline) tt {
- return math.sqrt(
- math.pow(tt, p1.x - p2.x, @as(tt, 2)) +
- math.pow(tt, p1.y - p2.y, @as(tt, 2)));
- }
- // Yes, it's this simple. If you feed it something for which
- // it can't convert shit properly, the compiler will just tell
- // you to fuck off. There aren't any traits or anything like
- // that.
- fn len(p1: Self, p2: Self) measure {
- // I can add type checks to the function itself
- if (tt == measure) {
- return len2(p1, p2);
- }
- // We can mostly just use consts everywhere for free
- return len2(
- .{ .x = @intToFloat(tt, p1.x),
- .y = @intToFloat(tt, p1.y) },
- .{ .x = @intToFloat(tt, p2.x),
- .y = @intToFloat(tt, p2.y) });
- }
- };
- }
- test "generics" {
- const p = [_]GPoint(f64) {
- .{ .x = 10.2, .y = 5.22 },
- .{ .x = 20.1, .y = 3.1 },
- GPoint(f64).center,
- .{ .x = -23.4, .y = 22.5 },
- };
- var f = GPoint(f64).len(p[0], p[2]);
- print("{}!\n", .{f});
- }
- // Errors are literally just simple error codes. These are uniquely
- // numbered throughout the WHOLE compilation, so there are no
- // collisions
- const FileError = error {
- InvalidValue,
- OutOfMemory,
- };
- // Use ErrType!Type to specify an error possibility
- // !type would mean any error type possible
- fn str_join_m(alloc: std.mem.Allocator, data: []const []const u8) FileError![]u8 {
- var len: usize = 0;
- for (data) |str| {
- len += str.len;
- }
- // 'try' / catch are just keywords to help with errors, they
- // aren't traditional exceptions.
- const buffer = alloc.alloc(u8, len) catch return FileError.OutOfMemory;
- // This does nothing in this case, but if the function returned
- // with an error, this would run.
- errdefer alloc.free(buffer);
- len = 0;
- for (data) |str| {
- std.mem.copy(u8, buffer[len..], str);
- len += str.len;
- }
- return buffer;
- }
- test "str_join" {
- const alloc = std.heap.c_allocator;
- const parts = [_][]const u8{
- "Mary ", "had ", "a little ", "lamb" };
- const str = try str_join_m(alloc, &parts);
- defer alloc.free(str);
- print("{s}\n", .{ str });
- }
- fn bad_fn() FileError {
- return FileError.OutOfMemory;
- }
- test "handling_errors" {
- // There are various ways to handle errors and null values:
- // ?type defines a nullable type:
- var x: ?u8 = null;
- // Ways to check for null:
- if (x) |val| {
- _ = val;
- // val is of type u8!
- }
- // If x is null, val = 0
- // These work with c pointers too.
- const val1 = x orelse 0;
- // Can execute arbitrary code with orelse
- const val2 = x orelse return FileError.OutOfMemory;
- const val3 = x orelse {
- print("x is null brah", .{});
- return FileError.OutOfMemory;
- };
- // Use try to automatically return errors that occur, and catch to
- // explicitly handle them
- try bad_fn();
- bad_fn catch |e| {
- _ = e;
- };
- _ = val1; _ = val2; _ = val3;
- }
Add Comment
Please, Sign In to add comment