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 extension methods to Url #2016

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Add extension methods to Url #2016

wants to merge 1 commit into from

Conversation

heaths
Copy link
Member

@heaths heaths commented Jan 22, 2025

Relates to Azure/typespec-rust#226

@heaths
Copy link
Member Author

heaths commented Jan 22, 2025

@JeffreyRichter @RickWinter what do you think? We're going to call this a lot in generated clients especially, but do we really want to extend the public API for that? If we were ever to replace url::Url with our own, I can think of more efficient ways to store data and make Url mutation cheaper since we'll be doing a lot of that. url::Url uses a single string as its storage so it's constantly encoding and decoding. Encoding to a string on write makes sense since strings are mutable in Rust, but we do a fair bit of decoding as well.

Given that, I'm tempted not to provide this for now, but wanted to put it out there. Even if we did replace Url with our own type and define these methods - which I think we would - the signatures will no doubtly be different. Then again, if we did replace it with our own type - especially after GA - we'd have to define all the same public APIs as well. So maybe we should newtype it now (well, after beta 1)?

/cc @jhendrixMSFT @analogrelay

@JeffreyRichter
Copy link
Member

I agree with you -- I would NOT provide this for now (and probably never provide it).

@RickWinter
Copy link
Member

I'm in agreement on not adding this right now.

@heaths
Copy link
Member Author

heaths commented Jan 23, 2025

I agree with you -- I would NOT provide this for now (and probably never provide it).

@JeffreyRichter do you mean the methods, or the type? We have to expose the Url type because it's used in policies. It provides nice helper methods for getting scheme, host, query parameters, etc., that policies need to do. I also expose it from clients for that very reason e.g., customers might want to index cached clients based on hostname.

It's just that url::Url is optimized for reading and, to a lesser degree, appending query parameters.

This isn't a question for beta.1, but pre-GA. I'm leaning toward at least newtyping it and expose those methods we want, which also means abstracting some things like query_pairs() or query_pairs_mut() to either return an impl Iterator or our own abstraction rather than url's types; fortunately, there's very little of its abstractions we'd have to otherwise hide.

@heaths
Copy link
Member Author

heaths commented Jan 23, 2025

BTW: the fact that these are public is the same problem as in other languages: they are defined in a crate for other crates to use so they have to be public but are intended for internal use. We could always document them as such, though we'd still not be able to break them...at least as easily; we can always bump dependency versions as needed and ship new dependent crates.

@JeffreyRichter
Copy link
Member

I meant the (extension) methods. We could provide the methods but not as extension?
If the url type is our type, then providing the methods may not be bad.
When I hear "extension methods" I interpret that as we don't own the type but we do own the methods and then we're logivcally altering the type that we don't own with our methods -- this is what gave me pause.
But, maybe I misunderstood?

@heaths
Copy link
Member Author

heaths commented Jan 24, 2025

When I hear "extension methods" I interpret that as we don't own the type but we do own the methods and then we're logivcally altering the type that we don't own with our methods -- this is what gave me pause.

I mean, that's why extension methods largely exist in many languages. Even in Rust they define "extension" methods (no official name I've seen, but everyone calls them "extension methods") for types - mainly traits - outside their definition precisely because they can't modify the definition. I see no functionality equivalent between top-level functions and extension methods apart from making extension methods easier to discover e.g., rust-analyzer would suggest them and auto-import functions. Is that the only part you don't like then?

@JeffreyRichter
Copy link
Member

I'm sure my lack of rust knowledge is affecting me here. If the url type is our type, then why would we need extension methods? Can't they just be methods on the type itself? To me, we either have formal methods that are past or the type of we have methods that are not past of the type. It seems strange to me to own the type and the methods but link them information together by extension methods as opposed to formal methods. But, if this is idiomatic for rust, then I can concede this.

@heaths
Copy link
Member Author

heaths commented Jan 27, 2025

@JeffreyRichter I think we're getting wires crossed here. I was describing why I'm declaring extension methods now, but also stating I think we should take ownership of Url before GA even if we just declare it as a newtype of Url. Yes, then we can add "native" methods as needed.

That said, yes, there's still a reason for extension methods even for types you own and it has to do with scope. Less-used or narrowly-scoped methods might be extension methods. Not saying we have to do that, though in this case there may be good reason since only our clients I'd expect to rewrite URLs while callers would more likely just want to extract data from them to make entirely new URLs.

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

Successfully merging this pull request may close these issues.

3 participants