Experimenting with variable reuse within declarations and its issues

It is apparently quite easy to think that b refers to something which it did earlier, when it actually refers to something newer than that.
This makes more sense as a problem if you rename it err instead.

1 Like

Only : part is for declaration, so suffering a bit of lack of aesthetics, something like

var1, ok := foo1()
var2:, ok = foo2()

could work. But overall this is not a good idea.
This is hard to spot and relying on “multiple return values can only be declared altogether” removes some mental overhead when reading the code.

This syntax is ambiguous still. How do you declare the ok but reuse the variable before? Your syntax cannot allow for it.

var, ok := foo()
var:, ok = foo()
var, ok: = foo() // same as the first one
var, ok: := foo() // ambiguous with `::` followed by `=`

There is a reason I said this twice:

I AM NOT LOOKING FOR SYNTAX SUGGESTIONS. PLEASE DO NOT GIVE ME THEM!


I thinking more and more that this idea has more cons than it has pros.

2 Likes
f,  ok := foo()
b, ok := bar()

Why the second ‘ok’ is not allowed? The language allow shadow .

But what if reusing only the most right-hand variable was allowed? (Kinda the same exception to the rule as or_* stuff)

1 Like

The language allows showing in nested scopes NOT within the same scope.

1 Like

Still no. I want things to work as expected.

1 Like

I can see how this can be useful in some cases (like you pointed out), but I think it’s too much of a niche to be bothered.

I’d find this useful to catch an error and handle it but still benefit from defer if err != nil semantics. It could be achieved by adding a keyword that sets the last return value like an or_return but doesn’t return so you can then do if err == .File_Not_Found right after

To me, a lot of this thread seems to be an effort to avoid a bit of typing by adding a lot of complexity. The juice just isn’t worth the squeeze.

  • Use different names for your error variables.
  • If you don’t care what the error code is, use the “Ignore it!” underscore.
  • You could maybe use one of the “or_” keywords to sidestep the entire issue.
foo_val, foo_ok := foo()
bar_val1, bar_ok1 := bar()
bar_val2, bar_ok2 := bar()
baz_val1, _ := baz()
baz_val2 := baz() or_else 42
1 Like

I sometimes like to shadow a variable, just to make sure I don’t accidentally use the previous binding further down in my code.
One trick can be to do a new scope with {} but that only works situationally.

I would like a syntax to opt in to shadowing, not so much for the convenience of the err/ok, but for the above reason. And the new binding would then not have to conform to any previous type, as it is a new binding.

Hi! I’m a complete beginner with Odin, but what I’ve been doing to avoid name collisions is using scopes like this:

	result1: V1
	{
		ok := false
		result1, ok = proc_call1()
		if !ok {
			fmt.eprintln("Error 1 ...")
			return
		}
	}

	result2: V2
	{
		ok := false
		result2, ok = proc_call2()
		if !ok {
			fmt.eprintln("Error 2 ...")
			return
		}
	}

I like using small scopes to keep my namespace clean, since many variables have a very limited scope of use. I also think it helps visually separate the code nicely.

Maybe it would be nice to have something like this instead:

	result: V = {
		value, ok := proc_call()
		if !ok {
			fmt.eprintln("Error...")
			return
		}
		break value // sort of return from the scope
	}

I think it would be a bit cleaner — though I guess it would have many other implications for the language — but the first solution works well enough for me

Oh yes I would love to be able to “return” a value from a scope!

1 Like

I also like scopes being expressions, like in Rust.

But I suppose that it is not really C-like enough for Odin, and is not giving any more semantic power than if you declared then assigned like you currently do. Except maybe having the infered type from the scope return type? :thinking:

So, hypotetically running with that, you might want to do a meta-programming step to support “scopes as expressions” and see how it goes.
Maybe using some custom attribute for your meta-program parser to search and transform from:
( As Odin attributes are normally for declarations, the attribute is on the declared variable, but you can do your own syntax it’s only for demonstration purpose )

@init_from_scope result := {
	value: V
	// [...]
	value
}

to:

	result: V = ---
	{
		value : V
		// [...]
		result = value // sort of return from the scope
	}

Anyway, I think that using scope for dealing with name collision is a good approach, even if the syntax is a bit more verbose than if we had “scopes as expressions”.

Have a great day everyone :smiley:

1 Like

The break value syntax conflicts with labeled goto in Odin. You can accomplish the effect of the second block with a procedure though.

1 Like

I wasn’t proposing any specific syntax when I mentioned break (it was just the first keyword that came to mind that wasn’t return). As far as I know, when using a nested procedure, variables from the outer scope aren’t accessible inside unless you pass them as parameters. That seems even less convenient if you need to use multiple variables from the outer context. Overall, as I said, using a scope without it being an expression isn’t really a problem, but in my opinion, having it as an expression would likely be a bit more ergonomic.

Scopes as expressions will NEVER be a thing in Odin. We experimented with it early on and found it was a very bad idea for the feel and general philosophy of Odin.

2 Likes