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

Restore int/f64 fallback for unconstrained literals #212

Merged
merged 1 commit into from
Sep 3, 2014

Conversation

nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented Aug 26, 2014

@alexcrichton
Copy link
Member

@emberian
Copy link
Member

The advantage here over what we used to do is that it only does the fallback when the type is unconstrained, rather than the "early" fallback that we used to do. (+1 ofc)

@lilyball
Copy link
Contributor

👍 Very much in favor of this.

@nikomatsakis
Copy link
Contributor Author

@cmr hmm, interesting point. I had forgotten about things like 1.to_string() or what have you. I should write up that difference explicitly in the RFC. Still, I think I prefer this formulation, particularly as it interacts with the defaulted type parameter fallback.

@emberian
Copy link
Member

@nikomatsakis I agree.

@glaebhoerl
Copy link
Contributor

Another alternative is to allow specifying the default on a per-module basis as Haskell does, or perhaps even per-scope. I remember this had tricky interactions with recursive modules, but maybe that was only because of global type inference (which Rust doesn't have)? It could also probably be added later in a backwards compatible way.

As for the particular default: what about i64? That seems the least likely to accidentally cause problems. I'm not sure if the performance impact would be meaningful for these "programming in the small" use cases, and a different type can be specified explicitly, anyways. (Prior art: Haskell defaults to Integer, which is unbounded. We don't have that option, but this is the closest we can get.)

@thestinger
Copy link

The i64 type would be a bad default because it's implemented in software on architectures with 32-bit integer registers.


# Detailed design

Integeral literals are currently type-checked by creating a special
Copy link
Contributor

Choose a reason for hiding this comment

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

Integer or Integral...

@pnkfelix
Copy link
Member

@thestinger the performance impact was addressed by @glaebhoerl : "I'm not sure if the performance impact would be meaningful for these "programming in the small" use cases, and a different type can be specified explicitly, anyways."

I would be inclined to consider i64 as the the default. Especially since the i suffix to get int is so easy to add, for those more concerned about performance while programming in the small

@thestinger
Copy link

I don't think a type without hardware support makes sense as a default. It's significantly slower (20-100%) when it does have hardware support, but it's actually emulated in software on a 32-bit CPU. On a 16-bit architecture, it would not exist at all without a significant amount of effort. It's typical to have an implementation of double-width integers (64-bit on 32-bit, 128-bit on 64-bit) but not quad-width - it would be so incredibly slow.

Rust has already experienced a lot of bad PR due to int being 64-bit in Rust on 64-bit architectures and 32-bit in C. However, that can just be considered a naming / documentation issue. On the other hand, I think it's fair to say that a language with a default integer type implemented in software is not much of a performance oriented systems language. Rust performing an order of magnitude slower than Java in typical micro-benchmarks doesn't seem like it's going to create interest in the language.

@glaebhoerl
Copy link
Contributor

The current situation is that there is no default, and programs with unconstrained integer literals are rejected. My belief is that we do currently qualify as a systems language. I don't think it's possible to become less of a systems language by accepting strictly more programs, no matter what the default is.

To put it another way: I don't think the choice of default is particularly consequential, for reasons outlined in the RFC.

@bluss
Copy link
Member

bluss commented Aug 27, 2014

I would like "integer literals" to be accepted for specifying f32 and f64 values in assignment, in &[f32] slices etc.

@Valloric
Copy link

Agreed with @thestinger. A systems language should default to a 32 bit int. We may not like it, but that's the world we live in. Making the size of a builtin vary with the CPU/architecture is just inviting bugs as well. C# has a clear specification for what each builtin means and it's invariant of the architecture. Ideally, compiling code for a different arch shouldn't lead to bugs that are incredibly hard to track down (or bugs at all).

@thestinger
Copy link

@bluss: I would too, but it's a separate issue from this.

@nikomatsakis
Copy link
Contributor Author

On Tue, Aug 26, 2014 at 11:40:19PM -0700, Daniel Micay wrote:

I think it's fair to say that a language with a default integer type implemented in software is not a performance oriented systems language.

I don't. I think this is actually quite unfair to say. As Felix and
Gabhor have already said, if you read the RFC, you will see that it
quite explicitly makes the claim (backed up by measurements) that the
use of the fallback integer type is quite unusual in production
code. Outside of tests, I found on the order of 50-75 cases of
literals whose types would fallback. I didn't count how many integer
literals appear in all the libraries and rustc, but I'm pretty sure
it's a much bigger number than 75. So these claims about our choice
fallback determining whether we are a "performance oriented systems
language" or not seem to be overblown, from what I can tell. Moreover,
the existence of a lint for unconstrainted integral types (as
specified by the RFC) seems to address that concern for any real
application.

@thestinger
Copy link

It's another issue that people are going to run into while trying the language that will give them a bad impression of the performance. It's already necessary to use unsafe in most high performance cost due to bounds check among other issues. The defaults are exactly what determines if it's a language that cares about performance, because you can drop down to low-level unsafe code in many. You already need to use #![no_std] and unsafe everywhere, adding another low performance default cements that it's not a priority.

@Valloric
Copy link

[...] the use of the fallback integer type is quite unusual in production
code. Outside of tests, I found on the order of 50-75 cases of
literals whose types would fallback.

In a way, that's even scarier. People will unwittingly hit it by accident on that one rare occasion and then it will become a Rust "gotcha" people will write blog posts about to warn others. If there's ever an Effective Rust book along the lines of Effective C++, I imagine it will have a rule like "always fully specify your integers, don't use the fallback."

IMO one of the critical questions one must ask oneself when designing a language feature is "will any part of this design at some point be called a 'gotcha'." This whole fallback-to-a-slow-integer idea fails that test miserably.

@asb
Copy link

asb commented Aug 28, 2014

@Valloric I do see this argument. I suppose it comes down to whether it's seen as problematic that most users of 'Rust in the large' will have a recommended set of lints? You could argue having flexible lints (and the ability to add new syntax extensions and lints on a per-codebase basis) is an advantage of Rust and something that hopefully allows it to scale down for small pieces of code or tests as well as up to very large codebases.

@Ericson2314
Copy link
Contributor

Could we feature gate fallback? Having to explicitly enable the feature for programming in the small might defeat the purpose, but I'd agree avoiding gotchas is more important.

@lilyball
Copy link
Contributor

@Ericson2314 I think feature-gating it completely removes the entire point of fallback, as you already suggested.

For what it's worth, I agree with @Valloric. I used to think that the fallback should be int, but I've been convinced by the arguments that int is a hidden performance gotcha, that is resolved by using i32.

@Ericson2314
Copy link
Contributor

Well, it is still easier to enable a feature gate once, than add suffixes in many places in your code when programming in the small. I'd guess I'd be fine with the a lint (as some suggested) being on by default too---a few warnings should not inhibit programming in the small too much.

@lilyball
Copy link
Contributor

A feature that always produces a warning is not an appropriate feature. Programming "in the small" should not lead to ignoring a bunch of warnings.

@Ericson2314
Copy link
Contributor

Actually, I think features that produce warnings are great. Holes and differed type errors with newer GHC allow one to program in an uninterrupted, while reminding you that you should clean them up later via a warning as they make your program bomb. You have the convenience and unimpeded flow of developing with scripting languages, with the safety of statically typed ones because you are reminded of every potential bug you introduce.

I view this as the same sort of feature: defaulting to some integer type is a code smell in systems languages. In fact with checked arithmetic (also good for prototyping, though not exclusively that), the wrong integer type could also make your program bomb just like these GHC features. But for prototyping or programming in the small, it is an acceptable temporary shortcut.

@brendanzab
Copy link
Member

I would be in favor of a warning.

@pnkfelix
Copy link
Member

pnkfelix commented Sep 1, 2014

On review I would like like to hear niko's thoughts on on this suggestion from @glaebhoerl

Another alternative is to allow specifying the default on a per-module basis as Haskell does, or perhaps even per-scope.

An attribute could be very nice here, especially w.r.t. future proofing future options for literal handling

@l0kod
Copy link

l0kod commented Sep 3, 2014

Agreed with @thestinger and @Valloric, the int may not be a good idea as a default type: rust-lang/rust#15526

If the initial value is positive, does a default u32 is less error-prone than a i32?

And does the f64 as a default for 32-bit or 16-bit architecture is good as well?


To our knowledge, there has not been a single bug exposed by removing
the fallback to the `int` type. Moreover, such bugs seem to be
extremely unlikely.
Copy link

Choose a reason for hiding this comment

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

About the int/uint, there is at least the rust-lang/rust#16736 issue (and I bet that other similar bugs will pop).

@lilyball
Copy link
Contributor

lilyball commented Sep 3, 2014

@l0kod Unsigned as default will be surprising to many people. i32 is much better than u32.

@brson brson merged commit 39be6aa into rust-lang:master Sep 3, 2014
@brson
Copy link
Contributor

brson commented Sep 3, 2014

Merged as RFC 56.

Discussion. Tracking

@UtherII
Copy link

UtherII commented Sep 5, 2014

I support the use of i32 as fallback instead of int, since it is :

  • fixed size.
  • faster on the usual CPU.
  • hardware supported by most CPU (even 16 bit)

nrc added a commit that referenced this pull request Dec 25, 2014
Change RFC #212 (integer fallback) to use `i32` instead of `int` as the fallback
withoutboats pushed a commit to withoutboats/rfcs that referenced this pull request Jan 15, 2017
@Centril Centril added A-primitive Primitive types related proposals & ideas A-inference Type inference related proposals & ideas A-typesystem Type system related proposals & ideas labels Nov 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inference Type inference related proposals & ideas A-primitive Primitive types related proposals & ideas A-typesystem Type system related proposals & ideas
Projects
None yet
Development

Successfully merging this pull request may close these issues.