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

Projects
None yet
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Aug 26, 2014

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Aug 26, 2014

@cmr

This comment has been minimized.

Copy link
Member

cmr commented Aug 26, 2014

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

This comment has been minimized.

Copy link
Contributor

lilyball commented Aug 26, 2014

👍 Very much in favor of this.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Aug 26, 2014

@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.

@cmr

This comment has been minimized.

Copy link
Member

cmr commented Aug 26, 2014

@nikomatsakis I agree.

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Aug 26, 2014

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

This comment has been minimized.

Copy link

thestinger commented Aug 26, 2014

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

This comment has been minimized.

@glaebhoerl

glaebhoerl Aug 26, 2014

Contributor

Integer or Integral...

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Aug 27, 2014

@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

This comment has been minimized.

Copy link

thestinger commented Aug 27, 2014

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

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Aug 27, 2014

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

Valloric commented Aug 27, 2014

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

This comment has been minimized.

Copy link

thestinger commented Aug 28, 2014

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

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Aug 28, 2014

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

This comment has been minimized.

Copy link

thestinger commented Aug 28, 2014

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

This comment has been minimized.

Copy link

Valloric commented Aug 28, 2014

[...] 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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Aug 28, 2014

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

This comment has been minimized.

Copy link
Contributor

lilyball commented Aug 28, 2014

@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

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Aug 29, 2014

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

This comment has been minimized.

Copy link
Contributor

lilyball commented Aug 29, 2014

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

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Aug 30, 2014

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

This comment has been minimized.

Copy link
Member

brendanzab commented Sep 1, 2014

I would be in favor of a warning.

@pnkfelix

This comment has been minimized.

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

This comment has been minimized.

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.

This comment has been minimized.

@l0kod

l0kod Sep 3, 2014

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

@lilyball

This comment has been minimized.

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 referenced this pull request Sep 3, 2014

Closed

Restore int fallback #16968

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

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Sep 3, 2014

Merged as RFC 56.

Discussion. Tracking

@UtherII

This comment has been minimized.

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

Merge pull request #452 from tbu-/pr_inti32
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

@chriskrycho chriskrycho referenced this pull request Feb 10, 2017

Closed

Document all features in the reference #38643

0 of 17 tasks complete

@chriskrycho chriskrycho referenced this pull request Mar 11, 2017

Closed

Document all features #9

18 of 48 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.