Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessing Environment Variables #841

Closed
runeimp opened this issue Mar 17, 2018 · 10 comments
Closed

Accessing Environment Variables #841

runeimp opened this issue Mar 17, 2018 · 10 comments

Comments

@runeimp
Copy link

runeimp commented Mar 17, 2018

Firstly I love the concepts behind Zig and just started playing with it yesterday. Very promising!

I'm trying to devise a good example for pulling environment variables. I've come up with the following thus far.

const std = @import("std");

pub fn main() !void {
    const allocator = std.debug.global_allocator;
    const env_map = std.os.getEnvMap(allocator) catch unreachable;
    const env_vars = &std.BufMap(env_map);
    const msg_format = "Hello, {}!\n";
    const name = env_vars.get("HELLO");
    const stdout = &(std.io.FileOutStream.init(&(try std.io.getStdOut())).stream);

    if (name != null) {
        try stdout.print(msg_format, name);
    } else {
        try stdout.print(msg_format, "world");
    }
}

But this seems horribly verbose but was the best I could manage to get through all the type errors. I believe this has much to do with #731 and other similar issues. But maybe I'm just overlooking something as well. Once I get a better understanding of some of these type issues I'd be happy to contribute updates to the docs. 😃

@andrewrk
Copy link
Member

Here are some suggestions:

-    const env_map = std.os.getEnvMap(allocator) catch unreachable;
+    const env_map = try std.os.getEnvMap(allocator);
-    const msg_format = "Hello, {}!\n";
-    if (name != null) {
-        try stdout.print(msg_format, name);
-    } else {
-        try stdout.print(msg_format, "world");
-    }
+    try stdout.print("Hello, {}!\n", name ?? "world");
-    const env_map = std.os.getEnvMap(allocator) catch unreachable;
-    const env_vars = &std.BufMap(env_map);
-    const name = env_vars.get("HELLO");
+    const name = std.os.getEnvVarOwned(allocator, "HELLO");
+    defer allocator.free(name);

The OS-agnostic environment variable API requires an allocator due to
the Windows API. If you are only targeting POSIX you can use
std.os.getEnvPosix which does not require an allocator.

@runeimp
Copy link
Author

runeimp commented Mar 18, 2018

Thanks for the suggestions! That all looks much nicer. But...

$ zig version
0.2.0.
$ zig build-exe hello_env.zig
/Users/runeimp/dev/hello/zig/hello_env.zig:11:38: error: expected nullable type, found '@typeOf(getEnvVarOwned).ReturnType.ErrorSet![]u8'
    try stdout.print("Hello, {}!\n", name ?? "world");
                                     ^
/usr/local/Cellar/zig/0.2.0/lib/zig/std/mem.zig:113:35: error: invalid cast from type '@typeOf(getEnvVarOwned).ReturnType.ErrorSet![]u8' to '[]const u8'
        const bytes = ([]const u8)(memory);
                                  ^
/Users/runeimp/dev/hello/zig/hello_env.zig:7:25: note: called from here
    defer allocator.free(name);
                        ^

These are much like the errors I was getting before I came up with the code I posted earlier. This on OS X 10.11.6 El Capitan with zig installed via Homebrew. Also /Users/runeimp/dev is symlinked to /Users/runeimp/Dropbox/UserENV/Profile/dev. Might any of that be part of the issue?

@andrewrk
Copy link
Member

Oops, my example code did not handle the error from getEnvVarOwned. You want to use try in front of it:

    const name = try std.os.getEnvVarOwned(allocator, "HELLO");

@runeimp
Copy link
Author

runeimp commented Mar 18, 2018

Almost there... 👼

$ zig build-exe hello_env.zig
/Users/runeimp/dev/hello/zig/hello_env.zig:11:38: error: expected nullable type, found '[]u8'
    try stdout.print("Hello, {}!\n", name ?? "world");
                                     ^

The type errors seem very hard to avoid. Seems like there is a basic concept of byte types, slices, string literals, and other string like things management I'm just not grasping in this language yet.

@andrewrk
Copy link
Member

Have a look through the docs: https://ziglang.org/documentation/master/

Feel free to ask questions on IRC, or message the email list if you need help.

@runeimp
Copy link
Author

runeimp commented Mar 18, 2018

I've been pouring over the docs since yesterday. They are lacking significantly in how to deal with type conversion. This is understandable with the language being so young. And is why I was offering to help with the docs once I was able to understand the expected methodology for handling what in any higher level language would simply be strings. The fact that it was not a simple matter to work out just accessing environment variables shows a pretty significant weakness in the language as it stands. I've done this sort of exercise with many languages including C, D, Go, and Rust and have never had so much trouble just accessing and printing an environment variable. Are there specific sections I should review in the docs that I may be overlooking? Or are you referencing the Casting section which has nothing but TODO notes?

I'm sorry if I'm sounding antagonistic. I really like what your doing with Zig and where it could be in a year's time is very exciting. But currently the methodology for handling the multitude of type conversion situations (how to cast, how to handle casting errors, why a variable set to []u8 can't hold [5]u8, const []u8, and especially &?const []u8 data, etc.) that are necessary to manage textual data is very confusing. The fact that all the functions I've tried that return textual data use different types makes it very difficult. I believe you've already mentioned creating a Zig by Example site. I look forward to that happening. Finish the Casting section of the docs would be a huge benefit to me in the meantime.

Thank you for all the time I'm sure was put into this project. I hope it is very successful and I look forward to learning more about it.

@andrewrk
Copy link
Member

expected nullable type, found '[]u8'

?? unwraps a nullable value. If you get this error, the type is not nullable.

Are there specific sections I should review in the docs that I may be overlooking?

This one: https://ziglang.org/documentation/master/#Nullables

It's important to understand types and what they mean, since types are the main safety feature in zig protecting us from memory corruption and other bugs like this.

Casting is a glaring hole in the documentation. I'll try to get to it soon. #367

@milahu
Copy link

milahu commented Jul 4, 2022

name ?? "world"

4 years later ; )

const std = @import("std");

pub fn main() anyerror!void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();
    const env_name = std.process.getEnvVarOwned(allocator, "HELLO") catch "";
    defer allocator.free(env_name);
    const name = if (env_name.len > 0) env_name else "world";
    const stdout = std.io.getStdOut().writer();
    try stdout.print("Hello {s}\n", .{name});
}

@praschke
Copy link
Contributor

praschke commented Jul 5, 2022

it's called orelse now.

const std = @import("std");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    
    const env_map = try arena.allocator().create(std.process.EnvMap);
    env_map.* = try std.process.getEnvMap(arena.allocator());
    defer env_map.deinit(); // technically unnecessary when using ArenaAllocator

    const name = env_map.get("HELLO") orelse "world";

    const stdout = std.io.getStdOut().writer();
    try stdout.print("Hello {s}\n", .{name});
}

@runeimp
Copy link
Author

runeimp commented Jul 7, 2022

Wow, COVID-19 killed my ability to keep up with other languages at all. Thanks for the updates @milahu and @praschke! Hopefully I'll have some free time to play with Zig again soon. 😀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants