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

[Feature] Support referencing existing variable values directly without need for get_env_var #623

Open
fiftydinar opened this issue Nov 30, 2024 · 16 comments
Labels
enhancement New feature or request

Comments

@fiftydinar
Copy link

fiftydinar commented Nov 30, 2024

Is your feature request related to a problem? Please describe.
Instead of need to do this:

import { get_env_var } from "std/env"

let home = get_env_var("HOME")
echo home

I simply want to do this:

echo ${HOME}

It is not convenient to use get_env_var every time you need to reference some existing variables.

Describe the solution you'd like
Maybe $var, ${var} or something similar can be used to reference those?

Describe alternatives you've considered
Besides keeping this as is (as worse alternative), I see no alternative.

Additional context
/

@fiftydinar fiftydinar added the enhancement New feature or request label Nov 30, 2024
@github-project-automation github-project-automation bot moved this to 🆕 New in Amber Project Nov 30, 2024
@b1ek
Copy link
Member

b1ek commented Dec 1, 2024

why not do this?

echo get_env_var("HOME")

also imo it is a better solution to allow for $ to be defined as a function, instead of creating a builtin:

import { get_env_var as $ } from "std/env"

echo $("HOME")

@b1ek
Copy link
Member

b1ek commented Dec 1, 2024

or maybe create a $ function in stdlib to allow for general bash syntax:

import { $ } from "std/util"

let a = "SMOL"
echo $("${nameof a},,") # smol

@fiftydinar
Copy link
Author

why not do this?

echo get_env_var("HOME")

It's not suitable if I want to do this:

var="${HOME}/Downloads/"

which I often do in bash scripts.

also imo it is a better solution to allow for $ to be defined as a function, instead of creating a builtin:

import { get_env_var as $ } from "std/env"

echo $("HOME")

Doesn't work, errors out (Unclosed interpolation)

or maybe create a $ function in stdlib to allow for general bash syntax:

import { $ } from "std/util"

let a = "SMOL"
echo $("${nameof a},,") # smol

Doesn't work, errors out (Unclosed interpolation)

I guess I'll wait for 0.3.6 version & try again.

@Ph0enixKM
Copy link
Member

Ph0enixKM commented Jan 6, 2025

@fiftydinar I like this idea to reference outer shell variables with $varname it's well separating the Bash variables from Amber ones. Also another approach... how about this syntax:

env ENV_VARIABLE as variable = "default value if not set"
env ENV_VARIABLE as variable
env ENV_VARIABLE

I think that this one is more flexible and let's you assign a default value (optionally)

@b1ek @Mte90 @hdwalters @mks-h you guys on board with this idea too? If so then we can add this feature in the upcoming version 0.5.0 (we will no longer release patch versions including new features, the iteration cycle will remain somewhat similar)

@Ph0enixKM Ph0enixKM added this to the Amber 0.5.0-alpha milestone Jan 6, 2025
@mks-h
Copy link
Member

mks-h commented Jan 6, 2025

I like the idea of declaring environment variables, however there are some considerations:

First of all, I don't see a need to use them differently from normal variables. And regarding syntax, we can't use the as keyword for aliasing, since it is already used for type casting. Additionally, I'd like to limit these env declarations to the top of the file for clarity.

And then there's the issue with data types — env variables should obviously be considered Text, but we also need to choose a way to work with the absence of value. So far we don't have any way of representing an absent value, with the closest thing being the soon-to-be-removed Failable type. Instead, we always force users to handle this absence immediately (through the failed block, or a default value). One option would be to implicitly default to an empty string. Also, with the get_env_var function we would be able to use the failed block to either return a default value, or do something else and fail — the latter not being possible with the default value mechanic.

P.S. In Bash there's also a technical difference between non-declared or unset variables and null variables ENV=/ENV='' (containing empty string). Although it seems that parameter expansions don't differentiate between them.

@hdwalters
Copy link
Contributor

hdwalters commented Jan 6, 2025

@Ph0enixKM I'm not sure I like this env ENV_VARIABLE as variable = "value" syntax; it doesn't seem a natural fit with either Amber variable or Bash environment variable syntax. As an alternative, I would like to suggest using the existing Amber variable syntax, except that variable names starting with a $ are automatically backed by an environment variable, and modifications to such variables automatically generate a Bash export statement:

// Internal variable usage
let answer = 42
echo "The answer is {answer}"

// Environment variable usage (scalar)
echo $PWD
echo "There's no place like {$HOME}"
let $PATH = "{$PATH}:/usr/bin/foo"

This idea has several advantages:

  1. It should require minimal changes to the Amber parser.
  2. It will fit in seamlessly with existing Amber code, and should therefore be easier to use.

We would probably have to enforce a space after $ to start a command $ cat file.txt $. Is that possible with Heraclitus?

N.B. If we do implement this, I think we should explicitly disallow "${PATH}", which would instead refer to an Amber variable PATH.

@hdwalters
Copy link
Contributor

@mks-h You claim that environment variables should always be treated as Text, but what about array variables? With my scheme, if we treat environment variables similarly to Amber variables, we should be able to support [Text] as well:

// Environment variable usage (array)
echo "Entire Bash version is {$BASH_VERSINFO}"
echo "Major Bash version is {$BASH_VERSINFO[0]}"

@hdwalters
Copy link
Contributor

hdwalters commented Jan 6, 2025

And perhaps the most canonical way to unset environment variables would be like this:

let $void = Null

I don't have any strong opinions on how to deal with a reference to an unset variable, but perhaps defaulting to an empty string would be the simplest way, and also consistent with Bash behaviour.

@hdwalters
Copy link
Contributor

hdwalters commented Jan 6, 2025

@mks-h I don't think it makes sense to restrict environment variable declarations to top of file. This seems overly prescriptive, and disallows use cases where we need to modify an environment variable between running subprocesses.

@mks-h
Copy link
Member

mks-h commented Jan 6, 2025

we should be able to support [Text] as well:

I don't think we can express a variable to be both Text and [Text] in Amber. Even if we merge the union types (we haven't yet, have we?), we would still not be able to express it (because it's a "one of" kind of type). The most natural type of an environment variable would be Text, because it is basically the raw input. And an array is really just a Text split up by a delimiter. Of course, having each env variable to be a [Text] split by whitespace is still an option, but that will make it less convenient to use with strings.

I don't think it makes sense to restrict environment variable declarations to top of file.

The idea is that environment variables are basically an API similar to CLI inputs. Therefore they should, first of all, be explicitly defined. And second, the top of the file would be a very logical and easy to access location for those who are reading the script.

disallows use cases where we need to modify an environment variable between running subprocesses.

I'm not sure what you mean, but it shouldn't because you should be able to modify them (without exporting) just like regular Amber variables.

@hdwalters
Copy link
Contributor

We can argue about specifics, but it would be useful to agree on a general approach. What do you think @Ph0enixKM, @fiftydinar, @b1ek?

@Ph0enixKM
Copy link
Member

@mks-h just like as keyword is used for renaming imports:

import { item as it } from "path"

I think that we can use it for renaming environment variables:

env VARIABLE as variable

If we accept this syntax, then it'd be easier to state of which type is the variable. We could also perform some Zod-like runtime type checking.

env VAR as var: [Text] = []

Default type would be Text.

Also. What do you dislike about this syntax, @hdwalters?

@hdwalters
Copy link
Contributor

hdwalters commented Jan 9, 2025

First some assumptions. When you write:

env VARIABLE as variable = "default value if not set"
env VARIABLE as variable
env VARIABLE

I think you mean "bring Bash environment variable VARIABLE into scope, and refer to it using Amber variable variable".

I don't like this because (i) you have to remember two different names VARIABLE and variable for the same thing, (ii) you can't tell from a reference to variable elsewhere in the code, whether it's backed by an environment variable or not, and (iii) the syntax (especially the long form) is unnecessarily complex.

With my suggestion, environment variables are differentiated by having an initial $, but are otherwise treated exactly the same way as classic Amber variables. They can be (i) set with let $answer = 42, (ii) retrieved with echo $answer, and (iii) interpolated with "There's no place like {$HOME}". The only difference is how they get translated to Bash code.

This way, there's less syntax for the user to remember: ordinary usage works like Amber variables, and string interpolation works (almost) like Bash.

The other advantage is that we can leverage the existing variable handling Rust code, which means it would be simpler to implement.

@Ph0enixKM
Copy link
Member

@hdwalters how would you syntactically differentiate variable from command:

$var

$var args$

Currently $var returns an error of unclosed command region. Under the hood we define anything between $ to be a command. We could instead make it a double $$ (in Heraclitus we can define two $ as a compound which then will not be treated as a region)

$$var

@hdwalters
Copy link
Contributor

hdwalters commented Jan 11, 2025

I previously asked whether Heraclitus was capable of distinguishing between $var and $ var. But if not, using $$ for commands might be a good alternative.

Is it possible to make Heraclitus also return $var as a single token, rather than separate $ and var?

@hdwalters
Copy link
Contributor

hdwalters commented Jan 11, 2025

Oh, I may have misread that; were you suggesting that we should keep $ command $ and use $$var for environment variables? Because I think it might make more sense to Bash programmers to use $$ command $$ and $var.

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

No branches or pull requests

5 participants