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

How to find in documentation that to_string is available for &str?
error: `var` does not live long enough
Thread '<main>' has overflowed its stack when allocating a large array using Box
Is it possible to control the size of an array using the type parameter of a generic?
What is a struct variant enum in std:serialize?
How to achieve equivalent of take_while on a slice?
Why and when should be comma used at the end of a block?
error: use of moved value res in Rust
How can you make a safe static singleton in Rust?
error: unable to infer enough type information about `_`; type annotations required
Glob imports of local enums in functions
How to replace a word in a file in a .txt
Create mutable iterator in nightly build after mut_iter removed
What is the default_type_params feature used for in Rust?
Why does the rust compiler generate huge executables?
How do I capitalize all the characters in a string in Rust?

Categories

HOME
entity-framework
events
openxml
whmcs
informatica
jersey-2.0
malware
iptables
flurry
ag-grid
joomla3.2
cisco
clickable-image
scrape
amazon-elb
jodatime
complexity-theory
google-tasks-api
robolectric
parceler
weex
dashdb
liferay-6.2
multi-upload
pdf.js
jstree
plyr
ibm-connections
epplus
lxml
stackpanel
jade4j
microsoft-ui-automation
tidal-scheduler
assert
right-click
python-jira
distributed-caching
oracle-bmcs
linq-to-excel
image-registration
android-5.0-lollipop
knockout-2.0
iptv
watir-webdriver
google-news
asp.net-web-api-routing
lvalue
perl-data-structures
annotatorjs
ipywidgets
fuzzer
dpkg
static-methods
powerpoint-2013
simian
sharepoint-apps
jemdoc
preferenceactivity
django-validation
wepay
opencyc
fanotify
ambiguity
extend
canopy
blockquote
replicaset
com0com
flow-js
utf8-decode
image-rotation
multivariate-testing
oracle-adf-mobile
wso2bam
code39
lsa
application-blocks
visual-c++-2005
mute
notifyjs
postgres-xc
hints
unicoins
dibs
server-name
kobold2d
nsfont
background-repeat
mmc3
dip
android-2.1-eclair
version-control-migration
server-load
regioninfo
account-management

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