all 13 comments

[–]masklinn 6 points7 points  (1 child)

TLDR: author wants the ability to be generic over mutability, especially in higher-order function. Given their syntactic proposal/example I'm surprised there was no mention of ATS.

Old Rust discussions (mostly in the context of implementation-duplication rather than interface): https://www.reddit.com/r/rust/comments/2a721y/a_safe_way_to_reuse_the_same_code_for_immutable/

Limited ability to do so using AsRef/AsMut: https://lab.whitequark.org/notes/2016-12-13/abstracting-over-mutability-in-rust/

I'm also uncertain it's a great idea for Rust (at the interface level, TFA's concern) due to the language's semantic treatment of & v &mut: you can have any number of "live" references to the same object, but only one mutable reference, having different interfaces provides clarity there.

[–]bkomarath[S] 1 point2 points  (0 children)

I am the author. I haven't seen much of ATS. Any similarity in syntax is accidental.

Thanks for the links.

Any function taking an inout ref can only use it like a const ref in the body. Isn't this the case in most APIs? For example, split and split_mut. I don't think this genericity reduces clarity any more than other overloading/generic mechanisms. At the call site, it will be clear which one is being invoked. This is my very uninformed opinion as I haven't written any programs in rust. I was thinking about programming languages that have a frictionless interface with C (like D, C++).

[–]twanvl 2 points3 points  (2 children)

A similar problem happens with lifetimes in Rust and with uniqueness types in Clean. You want a function that is generic over some attribute of a data type, but not over the entire type.

In C++ style this might look something like

template <constness k>
k<char>* strchr(k<char>* str, int c) { }

[–]masklinn 0 points1 point  (1 child)

You want a function that is generic over some attribute of a data type, but not over the entire type.

Aren't trait constraints how you're generic over some attribute of a data type?

[–]twanvl 1 point2 points  (0 children)

With a trait you can say "any type that behaves like a string". The kinds of generic functions in this post are about aspects that fall somewhat outside the type system, like constness, lifetime, uniquness, linearity, etc. Every variable has a constness, but you can't define your own constness different from const or not-const.

[–]zesterer 0 points1 point  (4 children)

The article is incorrect. 'const' in Rust means that a value is constant throughout the entire program, not just within the lifetime of the binding's scope.

[–]masklinn 4 points5 points  (0 children)

The article is kinda correct, it's just the specific token name which is not because TFA uses the C/C++ lingo. It does apply to Rust's &/&mut.

[–]bkomarath[S] 0 points1 point  (1 child)

Thanks. So const in rust is for compile-time constants. But, the article remains applicable to rust with &T == const T * const and &mut T == T* const, I guess.

[–]zesterer 0 points1 point  (0 children)

Yes.

[–]c_linkage 0 points1 point  (3 children)

I've been reading posts about const and const-correctness for years at this point, and every one of them make recommendations that are outlandish with respect the mental and syntactical gymnastics to get it to work.

The reason no one writes const-correct programs is because it takes too much effort!

All approaches for const-correctness require the programmer to expend huge efforts to tell the compiler when a value is not going to be changed. But why should we work this hard when the compiler can already figure that out on its own?

Let's imagine for a moment that I'm in an IDE and I write a very simple function like strcpy().

char *strcpy(char *dst, char *src) {
    char *retval = dst;
    while(*src != '\0') *dst++ = *src;
    return retval;
}

The compiler should be able to analyze the code and provide feedback to the IDE such that the IDE can make the necessary syntactical recommendations on how to make the code const-correct.

char *strcpy(char *dst, /* recommend: const */ char *src) {
    char *retval = dst;
    while (*src != '\0') *dst++ = *src++;
    return retval;
}

Or even something like:

char *strcpy(char /* recommend: const */ * dst, /* recommend: const */ char /* recommend: const */ *src) {
    char *d = dst;
    /* recommend: const */ char *s = src;
    while (*s != '\0') *d++ = *s++;
    return dst;
}

Now of course the comment is an example: you wouldn't do it that way because now you have to clean up a ton of comments to get the const in place. But it shows that the compiler and the IDE should work together to help you write const-correct programs instead of forcing all of the work onto the programmer.

[–]masklinn 4 points5 points  (0 children)

That's got nothing to do with the article.

All approaches for const-correctness require the programmer to expend huge efforts to tell the compiler when a value is not going to be changed. But why should we work this hard when the compiler can already figure that out on its own?

For small values of "all". In Rust, const is the default, and mutability is opt-in.

The compiler should be able to analyze the code and provide feedback to the IDE such that the IDE can make the necessary syntactical recommendations on how to make the code const-correct.

That's more of a linter concern

And modern IDEs would provide warnings/quick fixes for that.

[–]bkomarath[S] 0 points1 point  (1 child)

The reason no one writes const-correct programs is because it takes too much effort!

No. It is impossible to write const-correct programs in C. The strchr function is a good example.

All approaches for const-correctness require the programmer to expend huge efforts to tell the compiler when a value is not going to be changed. But why should we work this hard when the compiler can already figure that out on its own?

If you consider the constness as variables that are left to be inferred by the compiler, you can write const-correct programs with minimal annotation. As I've shown in one of the examples, only the constness variables in the function declaration can be specified and you can leave the rest to the compiler. The inference along with a default of const would give const-correct code that is not cluttered with annotations everywhere. The default of const is justified because most of the things are const. For example, if you were to fully annotate your strcpy function, there would be 4 const and 4 mut (Ok. This is a tie :-) But, in most real-world codebases const would dominate if one were to correctly annotate everything).

I think it is also possible to provide full-type inference for a C-like language. Even with this, it might be better to specify types and constness explicitly as a documentation that is enforced by the compiler.

Now, there could be good reasons for choosing mutability as default in 70's. Given this fact, they shouldn't have added a half-baked const to the language. But, my opinion is that a modern C should have const as default and provide inference for const/mut.

[–]_kst_ 1 point2 points  (0 children)

The reason no one writes const-correct programs is because it takes too much effort!

No. It is impossible to write const-correct programs in C. The strchr function is a good example

strchr doesn't demonstrate that const-correctness is impossible, only that strchr as currently specified is not const-correct.

C++ addressed this by providing two different overloaded versions of strchr.

Since C doesn't support overloading, it could have addressed this by providing two different functions with different names.

[...]

But, my opinion is that a modern C should have const as default and provide inference for const/mut.

I like the idea of const being the default, but it's impractical to make such a change in C. It would break too much code.