rust


How does Rust solve mutability for Hindley-Milner?


I've read that Rust has very good type inference using Hindley-Milner. Rust also has mutable variables and AFAIK there must be some constraints when a HM algorithm works with mutability because it could over-generalize. The following code:
let mut a;
a = 3;
a = 2.5;
Does not compile, because at the second row integer was inferred and a floating point value cannot be assigned to an integer variable. So I'm guessing that for simple variables, as soon as a non-generic type is inferred, the variable becomes a mono-type and cannot be generalized anymore.
But what about a template, like Vec? For example this code:
let mut v;
v = Vec::new();
v.push(3);
v.push(2.3);
This fails again, but for the last line again. That means that the second row inferred the type partially (Vec) and the third one inferred the container type.
What's the rule? Is there something like value-restriction that I don't know about? Or am I over-complicating things and Rust has much tighter rules (like no generalization at all)?
If I'm not wrong it does this:
let mut a;
a = 3; //here a is already infered as mut int
a = 2.5; //fails because int != float
For the vec snippet:
let mut v;
v = Vec::new();// now v type is Vec<something>
v.push(3); // v type is Vec<int>
v.push(2.3); // here fails because Vec<int> != Vec<float>
Notice I did not used rust types, but just for having a general idea.
It is considered an issue (as far as diagnostic quality goes) that rustc is slightly too eager in its type inference.
If we check your first example:
let mut a = 3;
a = 2.5;
Then the first line leads to inferring that a has a {generic integer type}, and the second line will lead to diagnose that 2.5 cannot be assigned to a because it's not a generic integer type.
It is expected that a better algorithm would instead register the conflict, and then point at the lines from which each type came. Maybe we'll get that with Chalk.
Note: the generic integer type is a trick of Rust to make integer literals "polymorphic", if there is no other hint at what specific integer type it should be, it will default to i32.
The second example occurs in basically the same way.
let mut v = Vec::new();
v.push(3);
In details:
v is assigned type $T
Vec::new() produces type Vec<$U>
3 produces type {integer}
So, on the first line, we get $T == Vec<$U> and on the second line we get $U == {integer}, so v is deduced to have type Vec<{integer}>.
If there is no other source to learn the exact integer type, it falls back to i32 by default.
I would like to note that mutability does not actually impact inference here; from the point of view of type inference, or type unification, the following code samples are equivalent:
// With mutability:
let mut a = 1;
a = 2.5;
// Without mutability:
let a = if <condition> { 1 } else { 2.5 };
There are much worse issues in Rust with regard to HM, Deref and sub-typing come as much more challenging.

Related Links

No Rust autocomplete in Visual Studio Code for external crates such as 'gtk-rs'
Convert a serde Map into Value
Rust closure errors -> …which is owned by the current function | capture of moved value:
Is it possible to destructure the `self` argument of a method?
Why does my Hamming weight function work in C but not in Rust?
Why does an if without an else always result in () as the value?
Why doesn't the rust crate openssl-sys compile?
Is allocating a struct on the heap or having a struct own a heap pointer more idiomatic?
How do I access files in a directory in Rust?
Conditional const definition based on a function call
How do I fix a missing lifetime specifier?
Get the minimum of two floating point values [duplicate]
unconstrained type parameter error
How do I initialize a static with calls to non-static functions? [duplicate]
What is the role of Send and Sync in libcore?
Error when creating a static variable: 'expected identifier, found `(` '

Categories

HOME
user-interface
workflow
couchdb
selenium-builder
filesize
risk-management
dronekit-python
openflow
moodle-api
flurry
azure-data-lake
graphql-js
cqrs
powermock
google-awareness
twisted
closures
uima
tfsbuild
bazaar
el
qa
exchange-server-2010
animated-gif
hdmi
amazon-iam
guice
delayed-job
osx-lion
xerces-c
keyboard-layout
variable-variables
grails-spring-security
grails3.2.0
jqgrid-asp.net
android-sharing
zend-server
dymola
rational-performance-test
thread-exceptions
logical
dmarc
msbuild-4.0
utf-16
verisign
seadragon
certificate-authority
odesk
boost-proto
textpattern
decidable
auto-generate
knife
vdm-sl
web-api
scala-macros
prism-4
nssortdescriptor
encryption-symmetric
cakephp-2.2
tabris
lmax
nachos
stripe.net
air-native-extension
jchartfx
windows-taskbar
assetic
unrealscript
jbox2d
linkbutton
workflow-manager-1.x
coordinate
struts2-s2hibernate
kobold2d
platform-independent
autosize
botnet
anonymous-types
channelfactory

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App