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

x as T shorthand for T(x)::T ? #57857

Open
StefanKarpinski opened this issue Mar 21, 2025 · 5 comments
Open

x as T shorthand for T(x)::T ? #57857

StefanKarpinski opened this issue Mar 21, 2025 · 5 comments
Labels
feature Indicates new feature / enhancement requests

Comments

@StefanKarpinski
Copy link
Member

It's become fairly common for people to write code like this:

n = Int(length(items))::Int

This is kind of verbose and redundant. I had always hoped that we might add type signatures for generic function such that the ::Int part is implied by the signature of Int(...) but that seems unlikely in the Julia 1.x timeframe. Perhaps a more pragmatic solution would be to have syntax sugar for the "convert and assert" pattern. We could have

n = length(items) as Int
# means this:
n = Int(length(items))::Int

Of course, in this case, I think you could just as well write n::Int = length(items) but that's not always doable.

@StefanKarpinski StefanKarpinski changed the title x as T shorthand for T(x)::T x as T shorthand for T(x)::T ? Mar 21, 2025
@adienes
Copy link
Member

adienes commented Mar 21, 2025

can't help but feel it's a little bit this meme

Image

I never quite understood why there is any opposition whatsoever to disallowing constructors from returning other types 😅

@KristofferC
Copy link
Member

The only reason for writing this is pretty much solely for the invalidation case and adding syntax just for that feels a bit excessive.

@nsajko nsajko added the feature Indicates new feature / enhancement requests label Mar 22, 2025
@StefanKarpinski
Copy link
Member Author

Yeah, maybe so. I would rather be allowed to restrict the type behavior of generic function, but that's going to be a breaking change. Not the feature, but using it on widely used functions like conversion and constructors.

@MasonProtter
Copy link
Contributor

MasonProtter commented Mar 24, 2025

Of course, in this case, I think you could just as well write n::Int = length(items) but that's not always doable.

I'll note that the only real reason this is a problem is that assignment returns the rhs of an expression, which is (IMO) really confusing and unfortunate.

Fixing that (I know it'd require 2.0) would also fix some other stuff like letting us do things like return (;x, y) = z to return (;x, y) instead of z.

Personally, I'd rather see the return value of assignment fixed than add an as syntax onto our gigantic pile of preexisting special syntax.


Maybe a compromise could be to have a Base.as(::Type{T}, x) where {T} = T(x)::T, and then freeze it's method table so that users can't override it?

@mikmoore
Copy link
Contributor

mikmoore commented Mar 24, 2025

I guess a "simple" solution would be something like @as(T, x) expanding to tmp=T; tmp(x)::tmp (making the temporary variable so that an expression for T does not risk being evaluated twice).

Although I would probably prefer @convert(T, x) yielding tmp = T; convert(tmp, x)::tmp since it's semantically closer to y::T = x and because convert is not "required" to make a copy. Although I acknowledge that convert methods are slightly less popular than "constructor-converter" methods so the day-1 support may be slightly less in aggregate.

Either of these can be done simply enough user-side, without any changes to Base. Although there is some (small) value to unifying it as part of Base.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Indicates new feature / enhancement requests
Projects
None yet
Development

No branches or pull requests

6 participants