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

Add Enum.size #5743

Closed
wants to merge 4 commits into from
Closed

Add Enum.size #5743

wants to merge 4 commits into from

Conversation

bew
Copy link
Contributor

@bew bew commented Feb 23, 2018

I just stepped on the need to know the number of enum members in an enum, and was surprised there wasn't a class method Enum.size or Enum.count, so here it is.

@Sija
Copy link
Contributor

Sija commented Feb 23, 2018

I'd use #size for consistent naming.

@bew
Copy link
Contributor Author

bew commented Feb 23, 2018

I was thinking about that, and finished with: Enum is not a container, it doesn't really have a size. So count seems to be the good word for this.

@makenowjust
Copy link
Contributor

However Enum has each method. It looks pretty like a container.

@RX14
Copy link
Contributor

RX14 commented Feb 24, 2018

If it's anything it's size, but can you provide a usecase?

@bew
Copy link
Contributor Author

bew commented Feb 24, 2018

Ok, I'll change to size.

My usecase is that I have a huge enum (~400+ members) that are used as a named index in an Array (or another container), and I want to create the Array with at least the minimal size (the numbers of enum members), to make sure it won't need to realloc or anything.

So basically I want to do Array(Something).new initial_capacity: MyBigEnum.size

@bew
Copy link
Contributor Author

bew commented Mar 10, 2018

Weird, the build failed with command bin/ci prepare_build took more than 10 minutes since last output Maybe it should be restarted?

@j8r
Copy link
Contributor

j8r commented Mar 20, 2018

@bew , it'll be clearer to rebase to one commit e.g Add Enum#size.

src/enum.cr Outdated
# ```
def self.size : Int32
{% if @type.has_attribute?("Flags") %}
{{ @type.constants.size - 2 }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this should be the popcount of all the constants &ed together.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The what? what does popcount mean?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number of non-zero bits. That's significant if there is a flag that sets multiple bits.

I'm not sure if that's the right behaviour, but generally this method is probably not that much relevant for Flag enums anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For enums it should be the number of unique values the enum has (currently this is not unique), for flags it should be the number of actual flag bits covered by all the options. For example in some enums you have A = 0b01, B = 0b10 and Both = 0b11, That's 3 flag constants but only 2 flag bits, which popcount solves.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question is, should .size return the number of constants or the number of unique values?

@bew
Copy link
Contributor Author

bew commented Mar 28, 2018

Quoting @straight-shoota on this comment:

The question is, should .size return the number of constants or the number of unique values?

enum A
  A = 1
  B = 2
  C = 1
end

pp A::A # => A
pp A::C # => A

https://carc.in/#/r/3scm
It looks like duplicated values are made aliases of the original value, so the number of constant should be the same as the number of unique values! (as iirc aliases are not constants)

Edit: seems like I'm wrong, it's just the printing that is 'broken' as it'll print the first enum member with that value, so the number of constant is still 3 in this case, not 2.
So @straight-shoota's question still stands

@bew bew changed the title Add Enum.count Add Enum.size Mar 29, 2018
@bew
Copy link
Contributor Author

bew commented Mar 29, 2018

I don't see a valid usecase where having the number of constant is more important than the number of unique values.
So I think it should give the number of unique values.

@bew
Copy link
Contributor Author

bew commented Apr 2, 2018

Ok I made it work for enum flags with popcount, but I didn't find a way to find the number of unique normal enum values without an "ugly" array alloc' just to count the number of unique values..

Any ideas?

@jkthorne
Copy link
Contributor

jkthorne commented Sep 5, 2018

@bew what is the status on this PR it looks like you might have some failing tests?

@bew
Copy link
Contributor Author

bew commented Sep 7, 2018

@wontruefree I need #5903 in order to access the values of each enum fields at compile time, and get the number of unique enum values for Enum.size.

And as it currently goes (see last Ary's comment on that other issue) it's too complex and useless... 😟

If you have a good usecase for this please go ahead

@bew
Copy link
Contributor Author

bew commented Sep 7, 2018

Actually I managed to get the values of each enum fields at compile time using a combination of @type.constants and @type.constant("Name"), shame on me I didn't really tried that earlier!!! (iirc I thought it would return the ASTNode of the constant, but it actually interprets and returns the value!)

And the problem of Field = 1 + 2 solved itself, as enum & constant top level visitor already uses the MathInterpreter I mentioned in #5903.

So there might not be any issues left, 'just waiting for the builds to finish.. 👍

end

it "gives number of unique enum values" do
SpecNonUniqueEnum.size.should eq 2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this should count number of enum members, not values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the big question of this PR I guess, but I can't find a usecase for this behavior..
Do you have one?

If the 2 behaviors are legit, maybe we can have 2 functions size & uniq_size or sth..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for uniqness if we're talking about members.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me size should be the number of members. If you want to know the number of uniq values, select all members and call uniq.

@bew
Copy link
Contributor Author

bew commented Sep 8, 2018

Since it seems to be the preferred behavior, I changed back Enum.size to count the number of members, should be good now

FWIW, to get uniq values, check the previous version: 9f58719

@bew
Copy link
Contributor Author

bew commented Dec 27, 2018

One of travis build fails for memory error (the fork one), otherwise it should be good to go?
Maybe @RX14 'd want to give it another look now?

# ```
def self.size : Int32
{% if @type.has_attribute?("Flags") %}
{{ @type }}::All.value.popcount
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still want to dedupe for flags, and not for non-flags enums?

Copy link
Contributor Author

@bew bew Apr 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seemed to be preferable to have Enum.size return the number of members for non-flags, I guess I should change it for flags too? (the popcount can always easily be done by the user, or added later under another name)

Or even rename it to Enum.count_members to avoid any mis-interpretation?

@bew
Copy link
Contributor Author

bew commented Sep 20, 2021

Hello, I'm cleaning up old PRs of mine on projects I don't follow anymore.

What do we do with this PR ? Close? or someone wants to take it?

@straight-shoota
Copy link
Member

If you don't plan to work on this, I'd suggest to close it. It's easy to open a new PR.

Maybe we should add an issue to track this enhancement.

@bew
Copy link
Contributor Author

bew commented Sep 20, 2021

Okay, closing it then

@bew bew closed this Sep 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants