Sorry if the title is a bit vague, but I wouldn't know how to phrase it precisely. Also, this question might have been discussed already, but once again I don't know what to search for exactly, so I couldn't find anything related. So, the following code compiles:
use std::fs::File;
use std::io::{self,Read,BufReader,Error,ErrorKind};
// IO
trait ReadNumeric<T> {
fn read_numeric(&mut self) -> io::Result<T>;
}
// Specialized for i32
impl<R: Read> ReadNumeric<usize> for BufReader<R> {
fn read_numeric(&mut self) -> io::Result<usize> {
let mut buf = [0; 4];
self.read_exact(&mut buf)?;
let x = usize::try_from(u32::from_ne_bytes(buf));
x.map_err(|e| Error::new(ErrorKind::InvalidData, e))
}
}
impl<R: Read> ReadNumeric<f64> for BufReader<R> {
fn read_numeric(&mut self) -> io::Result<f64> {
let mut buf = [0; 8];
self.read_exact(&mut buf)?;
Ok(f64::from_ne_bytes(buf))
}
}
trait ReadVector<T> {
fn read_vector(&mut self, n: usize) -> io::Result<Vec<T>>;
}
impl<T, R: ReadNumeric<T>> ReadVector<T> for R {
fn read_vector(&mut self, n: usize) -> io::Result<Vec<T>> {
let mut v = Vec::with_capacity(n);
for _ in 0..n {
v.push(self.read_numeric()?);
}
Ok(v)
}
}
// Sparse matrices
struct Matrix<T> {
data: Vec<T>,
indices: Vec<usize>,
indptr: Vec<usize>,
shape: (usize, usize),
}
impl<T> Matrix<T> {
fn read(path: &str) -> io::Result<Self>
where BufReader<File>: ReadNumeric<usize> + ReadNumeric<T>
{
let mut f = BufReader::new(File::open(path)?);
let rows = ReadNumeric::<usize>::read_numeric(&mut f)?;
let cols = ReadNumeric::<usize>::read_numeric(&mut f)?;
let nnz = ReadNumeric::<usize>::read_numeric(&mut f)?;
Ok(Matrix {
data: f.read_vector(nnz)?,
indices: ReadVector::<usize>::read_vector(&mut f, nnz)?,
indptr: ReadVector::<usize>::read_vector(&mut f, rows + 1)?,
shape: (rows, cols),
})
}
}
fn main() {
let _m = Matrix::<f64>::read("matrix.dat");
}
While if I drop the fully qualified syntax, the code does not compile any more (whether stable, or nightly):
impl<T> Matrix<T> {
fn read(path: &str) -> io::Result<Self>
where BufReader<File>: ReadNumeric<usize> + ReadNumeric<T>
{
let mut f = BufReader::new(File::open(path)?);
let rows = f.read_numeric()?;
let cols = f.read_numeric()?;
let nnz = f.read_numeric()?;
Ok(Matrix {
data: f.read_vector(nnz)?,
indices: f.read_vector(nnz)?,
indptr: f.read_vector(rows + 1)?,
shape: (rows, cols),
})
}
}
The compiler cannot deduce that it should use read_numeric<usize> for rows, cols, nnz, etc., albeit there is no ambiguity what types they should be. Say, (rows, cols) is used in the shape field, which has type (usize, usize). Is automatic type inference in this case something that can be added to the compiler, or are there design reason for why that can't be done?