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

Remove "final" keyword to allow extending #25

Closed
wants to merge 1 commit into from

Conversation

dvankley
Copy link
Contributor

@dvankley dvankley commented Apr 7, 2014

No description provided.

@ramsey
Copy link
Owner

ramsey commented Apr 7, 2014

Can you provide more details/use cases on why you wish to extend the Uuid class? The choice of using the final keyword was purposeful.

@dvankley
Copy link
Contributor Author

dvankley commented Apr 7, 2014

Sure thing. We're looking to use a modified version of the type 1 UUID to allow us to generate unique type 1 UUIDs for past data. We're customizing the UUID because the data was not stored with 100 nanosecond resolution timestamps and we still need to guarantee uniqueness. We can't use other UUID types because we're using UUIDs as the primary ids for time series data in Cassandra (https://github.com/Pardot/Rhombus), so it's essential to have the ids sortable by time for range queries to work correctly. Initially we just created a class to wrap and manipulate your standard UUIDs to do what we want, but some functions (such as getTimestamp) validate the variant field, which we are using to denote that our timestamps are non-standard. So we'd like to extend the UUID class to make our code cleaner and properly recognize our modified variant field.

@stanlemon
Copy link

Hey @ramsey just curious if you could expand on why it was purposeful?

@ramsey
Copy link
Owner

ramsey commented Apr 7, 2014

@marijn, would you like to weigh-in on this? I know you were advocating for the use of the final keyword a while back.

@marijn
Copy link
Contributor

marijn commented Apr 7, 2014

Hell yes. On the road right now but will reply tomorrow.

Verstuurd vanaf mijn iPhone

Op 7 apr. 2014 om 17:41 heeft Ben Ramsey notifications@github.com het volgende geschreven:

@marijn, would you like to weigh-in on this? I know you were advocating for the use of the final keyword a while back.


Reply to this email directly or view it on GitHub.

@eduardosoliv
Copy link

+1 remove final

@marijn
Copy link
Contributor

marijn commented Apr 11, 2014

@dvankley would you mind posting some of that old UUID wrapper class that you have? Perhaps also a test if you have one? I don't really understand what you're doing what can't be done without inheritance...

@ramsey
Copy link
Owner

ramsey commented Apr 11, 2014

One of the primary reasons for the use of "final" is that this is based on a specification. Therefore, it can be trusted (I hope) to match the spec. A subclass might not follow the spec, so anyone using that subclass cannot trust that the UUIDs they are generating follow the spec. Additionally, the UUID should be immutable. Keeping the class "final" ensures that subclasses do not try to introduce mutability.

@dvankley, one idea I have that might help is for Rhumsaa\Uuid to provide a fromTime() method (like its fromString() method). Currently, to test proper UUID creation from known timestamps, I use a static property that I set to a value that looks like the output of PHP's gettimeofday() function. Then, when creating version 1 UUID's I can ensure that they are identical to what I expect. See here for an example:

Uuid::$timeOfDayTest = $timeOfDay;

So, a fromTime() method would work similarly. You could pass in specific time properties (like those returned from gettimeofday()), along with an optional node and clock sequence, and this would generate a UUID according to previously-determined times. This might work for your needs, rather than having to create your own UUID variant.

Thoughts?

@dvankley
Copy link
Contributor Author

Your reasoning behind using "final" makes sense, but I'm not quite on board with the conclusion. To me it seems like even without "final" your class is still guaranteed to follow the spec and be immutable. I would say responsibility for making those and any other guarantees for any subclasses would fall on their writers, and users of those subclasses would have to consider the contract of the subclass they were using.

The fromTime() method would be helpful, but we're already using the fromString() method with a little bit of sprintf to achieve basically the same thing, so it's probably not worth your time to implement just for us. Thanks for the offer, though.

@marijn
Copy link
Contributor

marijn commented Apr 14, 2014

@dvankley I'm still interested in seeing the original test and corresponding class. Perhaps that will make it possible to provide you better arguments why final is the way to go.

@dvankley
Copy link
Contributor Author

The module we're using it in isn't open source, so my company would probably get pissy if I posted it here. Really the only stuff we're doing beyond just the standard building UUIDs from component fields is storing some additional information in the timestamp value to guarantee uniqueness, since all our incoming timestamps are only second precision. It's nothing fancy and works fine in a wrapper class, but I thought it would be cleaner from a user's perspective to have it as a subclass.

@marijn
Copy link
Contributor

marijn commented Apr 14, 2014

but I thought it would be cleaner from a user's perspective to have it as a subclass.

Composition > Inheritance. Wrapping is way better in my opinion.

@stanlemon
Copy link

You can make that argument, but I think all you're doing is encouraging someone to fork your repository unnecessarily. I'll agree with you that I prefer composition over inheritance, but I prefer choice even more so. I think if your UUID class was a value object you'd have a better case for making it immutable with final. However, your value and construction are interwoven and ergo my disagreement with the use of final here.

@ramsey
Copy link
Owner

ramsey commented May 1, 2014

After much thought and discussion with others, I am inclined to accept this pull request to remove the final keyword.

Any other thoughts or rebuttals?

@ramsey
Copy link
Owner

ramsey commented May 1, 2014

Also, when I accept this PR, it will resolve #23.

@dvankley
Copy link
Contributor Author

dvankley commented May 1, 2014

Sounds good to me!

@marijn
Copy link
Contributor

marijn commented May 1, 2014

I don’t think it’s necessary — albeit that I haven’t had the time to formulate alternatives due to a lack of time — especially not for the reason of extensibility.

@ramsey
Copy link
Owner

ramsey commented May 1, 2014

I don't think it's necessary, either, but I'm failing to see good arguments for keeping the class final. People will naturally want to try to extend it and add to it, and I don't see a reason anymore why we shouldn't allow that.

@marijn
Copy link
Contributor

marijn commented May 1, 2014

Because you'll have to support the public and protected API from that point onwards.

@stanlemon
Copy link

@marijn that's already being done... they're called tests.

@marijn
Copy link
Contributor

marijn commented May 1, 2014

@marijn that's already being done... they're called tests.

What are you trying to say with that? I'm not sure I understand you.

My point is that if Ben decides to drop the final keyword all protected methods and fields have to be kept backwards and forwards compatible if he wants to keep releasing semantic versions.
If he doesn't all he has to do is support the public API.
I'm not sure how your comments regarding tests relate to my support argument.

@stanlemon
Copy link

Semver allows changing of protected/private code in a Y release. It restricts changes to the public API through X. Removing final doesn't suddenly make things not exposed by the class contract locked in on semver. Check out item 7 on semver.

@marijn
Copy link
Contributor

marijn commented May 1, 2014

My mistake, I thought this would considered part of the public API.

@ramsey
Copy link
Owner

ramsey commented Oct 30, 2014

I merged this into the 3.0 branch in commit dc1b735.

Thanks!

@ramsey ramsey closed this Oct 30, 2014
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

5 participants