Entity name collision and scope of variables, constants and functions

I am brand new to Zig - admire and enjoy it even though there is a deceptive learning curve to it. Used to most of the basics like tooling, pointers, syntax and library etc but one thing catches me off guard that I think I know the Zig answer to, but don’t like it.

Is there a way to specify scope to a variable. To give you an example,

I work on a “class” struct, and it grows. In order to have sanity, I have a single noun parameter called count, in many places. This works perfectly, until, a few days later, I have to have a function called count.

The function name count makes sense in context, and since size, len is already used or implied/connected to other things means that I am running out of nouns for a length of an item - meaning depending on my choice I may have to change something in many places.

I do appreciate the fact that Zig is doing this to avoid collision as function references can be used “like variables” and various others, but - and I will be happy if there is a qualifier that I am missing, but it is a huge shortcoming to me in a modern language that I cannot qualify where a name comes from.

    pub fn clash(count: usize) void {
        std.debug.print("{}}", count);
    }

    pub fn count(self: *Self, str: []const u8) usize {
        const c= std.mem.count(u8, &self.buffer, str);
        return c;
    }
src/utils/pascalstring/PascalString.zig:34:18: error: function parameter shadows declaration of 'count'
    pub fn clash(count: usize) void {
                 ^~~~~
src/utils/pascalstring/PascalString.zig:59:9: note: declared here
    pub fn count(self: *Self, str: []const u8) usize {
    ~~~~^~

I already follow the Zig naming conventions, which I have no issue with. For single syllable nouns however, the naming does not differentiate. I know various other languages has/had this issue - and the “end-user” developers solution to that was usually (very) ugly and counter intuitive e.g. Hungarian notation to parameters.

I obviously want to avoid that. I also want to avoid over-complicating local variables, and even worse, notating or abbreviating parameters, variables or any other types.

Am I missing some trick, is it a concern to others, or is the way it is going to be forever and make my own a long term plan.

4 Likes

count is a very vague name, count what?

Use more descriptive names and you’ll mostly avoid this problem

1 Like

@vulpesx - as much I appreciate your help on various other topics, I simply cannot agree here. In context count can mean many things - and I honestly don’t want to write sentences for a single item that collide, for which I can see the meaning of it on a few lines of code.

To make matters worse, like I said, it slowly creeps up on you, as you generally, with refactoring sometimes only stabilize names a few days down the road, meaning labels change as you work through it; and then this can become really tiresome; even though for much of it there is a scope involved that should have protected you (to some extent at least)

So how do one safeguard against this… And it seems like either writing sentences (for variable names), shortening it undescriptive or making things ugly in other ways (not natural).

1 Like

I don’t understand why you are trying so hard not to type countStr or num or something else.

I find it ridiculous when programmers try so hard to avoid typing such a small amount of characters

1 Like

Please don’t find it ridiculous. It is obvious, as it is just a matter of time until you have two thousand combinations of count*****

I don’t tell you how you should play golf (even the pros have different methods and styles). I am asking you whether there is a different club in the bag, and whether there will ever be a loft wedge invented soon.

If you tell me no, then I will start to use my putter for chipping (hungarian notation or other). So gain, don’t tell me how to play, cause I have to live with my own game - tell me whether there is or will be a club.

3 Likes

You clearly understand that how you want to play the game isn’t accepted by zig.

You have the solution that I provided, as well as multiple that you came up with yourself.

I am not telling you what to do, I merely gave an answer to your question.

zig doesn’t have some magical thing that lets you use a name multiple times without a clear separation between the two, it will never have such a thing as it would create ambiguity which is the antithesis to readability

It is pretty clear which is preferable, a million different count, or one Class.countStr, one Class.clash(num:...).

I still find it ridiculous that you want such a thing, especially when your only reasoning amounts to because i want to.
I don’t want that, but neither of our opinions matter, as we are not the creators/maintainers of the language. we can only speak our opinion and hope.

1 Like

Because a rope, is a rope is a rope (Leisure Suit Larry - 1980s…). @vulpesx - I have stated the issue, if there is somebody on the design team then maybe they can consider.

Judging by your response I will (have to) take a different systematic approach to naming things. And sadly, having it as countStr is just a hungarian notation; that again assumes context and meaning, which means it needs to be followed throughout otherwise it looks really bad, really quickly - even confusing if not consistent.

I leave it there - thanks for taking the time to respond; even though I was hoping to miss a language trick and didn’t find it as per the discussion.

the problem is not that a rope is a rope.
its that there are two kinds of rope, they do different things, they can hold different weights.

yet you are referring to both of them simply as rope, how is zig to know (or anyone reading the code) which rope you are referring to.

Something zig could do (some languages do this):
since the count parameter in the clash function is in a lower scope it could take priority, but what if you want to call the count function. well you would have to do something like Class.count() or @This().count(),

what’s the difference between that and using different names. I think if zig did that, it’d be more work on the programmers side to make sense of the code, and it’d be more work for zig to do.
Not by much on both accounts, so i dont think it matters much.

But zig doesn’t do that, and there is really no reason to change, beyond “me want smaller names”

I also argue that the current behaviour promotes more descriptive names which improves readability, something zig aims to do.

This is so inconsequential, one side is mostly opinion, the other side is also mostly opinion.

1 Like

You’re not missing a trick, as already discussed.

Whenever I’ve hit my head on an opinionated Zig error, I’ve adapted (no choice), but I’ve also grown to understand and appreciated the design decision. From what I’ve seen Zig always favours unambiguous simplicity. If Zig conceded on that principle the learning curve wouldn’t be arguably “deceptive” it’d just be outright steep.

In this case as @vulpesx points out it’s language complexity vs a little creative naming. Going full hungarian notation isn’t necessary that’s a bit of a straw man. countString, getCount, countItems, countBytes, byteLength, stringLength depending on context, plenty of options!

Anyway, hope you find joy in Zig. There are things I don’t like, but those choices led to the whole package that is something unique.

4 Likes

@dbushell , @vulpesx

I have taken the time now to skim through a large part of the std module.

They do one of two things:

  1. Abbreviate the living daylights (primarily parameters).
  2. Make multipart snake_case variables and parameters except camelCase for function parameters (parameters that reference a function). The snake case generally are two nouns (as per @vulpesx suggestion).

That said, the chances of conflict when extending the struct still exist - even in the std code there are obvious nouns that need to be avoided going forward.

The bottom line as per what I see, either abbreviate (parameters mostly) or make at least a two_noun variable (for members and locals), in order to avoid camelCase function conflict.

And yes, all style is just opinion - 6 of one, half a dozen, personally I would much rather describe the origin though this (if in conflict) than having to think of different ways to call a rope something other than a rope.

But - it is what it is…

The take away… similar to old C style, you have to be very wary of how you name things, because the risks of conflict and the cost of changing is always there.

Have a plan of attack - don’t think lightly of it.

I think avoiding things might be helpful for a handful of basic things, but I think beyond that it doesn’t make much sense, instead I would accept the necessity to edit code as changes arise and check that you know how to do a variable rename with your editor that is quick and painless, renaming the variable everywhere at once.

I don’t think we should plan our code around trying to avoid future code editing, if your cost of changing is so high that you intend to plan your code design around it, my suggestion would instead be to reflect on your editing tools and habits and how to reduce the cost, by either adapting the tools, or getting new ones.

Having to rename a few variables shouldn’t be something that registers as grunt work.

2 Likes

I also have some war with the name restrictions, but learned to live with it.

You’ll learn to like the naming restrictions. Everybody gets collisions sometimes, I bet even Andrew has had moments where a name that would be perfect was already taken. But it is one of the things that make Zig so readable. Inside the scope of your struct, you can count on count being the function count, and nothing else, no matter how much you jump around the code, and how deeply nested you get.

2 Likes

I have good tools… as good as a relatively new technology has that is not completely mainstream.

On “having to rename a few variables”… I would much rather choose a method of work that involve having as little as possible change, especially changes to code that has nothing to do with the intended code change (which is an obvious side effect here).

PS: I work on a daily basis on a heap of technologies; with most things that need to have been done before the project started, so one of the main reasons for me choosing Zig over C is its code organisation, with its namespaces and files as structs are for my money, on par or better than most across the board; which makes it a pity that I will have to change variable names to avoid conflict.

As somebody that works on heaps of technologies, it makes sense for me to rather go by convention… which will look out of place - this is my own code but I will do a poc for myself in (like Visual C++ of old)…

m_ for members
p_ for parameters
Or something similar, which can possibly avoid conflict without having to invent names. I don’t like it, but I will get used to it (where have I heard that before) :slight_smile:

@LucasSantos91 - there are tons of things making Zig readable/safer from a syntax perspective. Sadly the horrible variable names I choose and its context is not what makes the code readable imho. Forcing me to not collide names actually gives me better opportunity to create worse names (actually asking for it)

On your second point, that is exactly my issue - count as a local variable/parameter, count as a function and count as a type are 3 different things.

Again - these names gets mangled at in any case…? So I see this as a shortcoming, not as a necessity.

I will live with it, one way or another.

Consider this line:

const a = &count;

As long as you are inside the struct, you know exactly what it means, without any context. Even if you were skimming through the struct and stopped at a random point, you still know what it means. You are taking a pointer to the count function, there is no other possibility. When shadowing exists, you need to consider every block that came before this line. Count could have been redeclared as a parameter, or maybe inside a block.
I guess the best thing to do is just not overthink parameter names. You can change them at any moment, without affecting downstream code. If the only name that comes to mind is count, just call it count_arg and move on. I agree that it is less aesthetically pleasing, but it is way less of problem than people make it out. As long as it’s descriptive, it’s ok to be ugly. In this case, it makes it quite obvious that you are dealing with a parameter, instead of the count function.

10 Likes

You’re not missing anything. It’s a problem we all deal with. There’s no solution to this since the underlying cause is the loss of inflections in the English language. That an imperative would collide with a noun is actually kind of bizarre.

7 Likes

@gkell I don’t know about everyone else, but it would help me understand your problem if you could provide a mininal code example of the issue. I may be a bit thick, but I’m having trouble picturing a scenario where a struct could contain 3 or more declarations that could unambiguously be called “count”.

You say that adding context to the names (i.e. namesCount, or users_count) would be unacceptable, and that’s fine, but it might make the conversation less combative if you could present a clear example of the issue you’re having, rather than us just going back and forth on whether or not is a good idea “in general”.

While I personally am in favor of the way Zig prevents collisions, I’d very much like to wrap my head around the issue you’re experiencing.


And if all else fails, you can always resort to the cursed count, count_, count__. Many may scoff at this (It’s not my favorite solution), but it it something you can find in Haskell and IIRC some Lisp dialects for naming alternate “prime” versions of functions. i.e. sort, and sort'.

1 Like

so we can agree that the problem is your choice of names

it also gives the opportunity to create better names, whether they are better or worse is entirely up to you.

but considering

I think you are correct that you will make worse names. But that’s ok because you will improve with practice :slight_smile:

my advice is: describe what it is/does. You don’t need a whole sentence just one more word, you can also shorten words, though I’d recommend you stick to well known abbreviations.

Also stop caring about the asthetics of code, its not meant to be pretty its meant to zap a rock to do math

2 Likes

I hear you. And I am not arguing there - I understand and have respect for for your and other comments and suggestions. All viable options…

That said, and I said it before, is that for a brand new/modern language I thought this may have had a better solution.

Again, it is what it is, and I (personally) will first go a conventions route for my endeavors… As I come from an “accounting” background. It is questionable to do something in a certain way a few times, while doing it over and over shows more admirable consistency and predictability.