Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Looks like inferred return type on the `planets` function on the first page?

I'm not a big fan of this. IMHO local inference is great, but it makes things so much better when function signatures are explicit.



D would be ruined without it. The ability to return so-called voldemort types is not only hugely beneficial for expressiveness but also efficiency (i.e. particularly avoiding the heap).

Syntax toa apply some kind of constraint to the return type would be ok.


When I looked up the example for D, it looks like something that could be named with e.g. Rust's impl feature. In Rust you can return an "impl" of an interface, which is an object with concrete but unnamed type that implements a known interface. It similarly avoids the heap and avoids virtual function calls, without exposing the concrete type.

https://doc.rust-lang.org/edition-guide/rust-2018/trait-syst...


If you have a publicly visible interface, that's a name. It may be a name of a base type but it's still a name. IIRC, you can't even typeof() an instance of a Voldemort type.

That has some implications for how Voldemort types work that can't be replicated with anonymous interface implementations. The main one is, Voldemort types are very thoroughly sealed. There is no way to create an instance of one outside of the function where it's defined. With an interface, anyone else could come along and create their own implementation.


You may be thinking of Java's idea of an interface, which is a type (with specific subtyping behaviors). Traits in Rust are not types. There are two different ways to reference an object which implements a trait indirectly (actually more, but these are the dominant ones):

- a `Box<dyn Trait>` is like a Java object referenced by an interface. Everything uses dynamic dispatch, and it is an actual concrete type (though the actual "underlying" type is type-erased).

- an `-> impl Trait` is an existential type which uses a trait as a bound, which should be equivalent to D's "Voldemort" types, except that it can still satisfy Trait requires for other functions. For example, if you `-> impl Iterator<Item = u32>`, you can pass that result to a function expecting an iterator of `u32`. However, the type is fully defined by the callee and can't be instantiated/inspected externally.


> With an interface, anyone else could come along and create their own implementation.

Not true in Rust, because the type returned by the function is a concrete type.

I think we may be overloading “name” here, a bit. If you return an “impl” in Rust, you have to name an interface, but you can’t actually create new instances of the concrete type returned by the function.


> Rust, you have to name an interface, but you can’t actually create new instances of the concrete type returned by the function.

I think that's the distinction that really matters. The thing that's neat about Voldemort types, and gives them their interesting properties that are distinct from anonymous types, is that they have no name at all. Not even an interface or trait name.


What would be a concrete use case which benefits from this? I am not experienced with D, but it just seems like it would make code more obscure


There's a bit more explanation on the D wiki: https://wiki.dlang.org/Voldemort_types

I don't really intend to say whether they are better or worse than other ways of accomplishing similar things. Just that they're different.


Yes, from that explanation it sounds like they are equivalent to Rust’s impl return types.

Note that interfaces in Rust are not types, they do not name types. A value cannot have interface type. What happens when you return an “impl” type is that you return some unspecified type, but that type must implement the specified interface.

You could translate the D example to:

    trait HasGetValue {
        fn get_value(&self) -> i32;
    }
    fn create_voldemort_type(value: i32) -> impl HasGetValue {
        ...
    }
The “create_voldemort_type” function simply returns a value of unspecified type. As far as I can tell, this is equivalent to the D code, except it doesn’t use type inference for the function type.


Not really. Part of the point of voldemort types is that no information about the type is 'leaked' outside the function. In this case, the trait 'HasGetValue' is leaked and can be used by other code.


When would you want to have an interface such that nothing about the return type of a function is known to the outside world? I'm genuinely asking; I just don't understand the utility of this concept.


I don't think anyone's trying to argue about whether it's better or worse than the Rust concept. Just that it's subtly different.


I'm not interested in comparing it to the rust concept. I'm just curious why this is something people find valuable in D, and why another commenter would call it a feature D "would be ruined without"


The commentor is just mistaken. The two do the exact same thing.


That's fine, but I'm not interested in comparing them and I still don't understand what the benefit is


I sort of agree, but enforcing this only on things public / exported can be a nice compromise.

(I mean this as a general statement. Idk how the language handles this)


I actually like the option to have both inferred parameter and return types, primarily because they help in writing code while prototyping quickly with several types.

Once the code is well defined I then start adding the type annotations , often times using the ide tooling to auto generate them.

I think a good balance would be that all published packages should have type annotations added in their source code for clarity while short scripts could do without them.


Idk I mean maybe it's a matter of taste, but I just never felt like it was that cumbersome to write type names in the function signatures. In a short script it's not like you would usually have the dozens or hundreds of function signatures it would take to make this feel like drudgery.


Well think about writing functions inside a repl or interactive environments like jupyter notebooks or just plain scripting. Enforcing type annotations add little value in those cases and end up making the language ill suited for such use cases.

Whole form type inference is actually a super power that allows for writing extremely expressive code without giving up type safety.


I like explicit types on functions too.

However, it might be what I’m used to.

Do you think this would be less of a problem with editor/IDE support? Using colors, or other visuals, to infer and show the types while editing might overcome this desire.


Rust did not choose to infer types in signatures for UX and stability reasons. If you infer types in signatures, then a change in the body of the function can change the type of the function, which makes dealing with backwards compatibility harder. Also, it leads to weird "errors at a distance."


I call this property "an accidental complexity" - when changing one piece of code causes failures in other, seemingly unrelated parts of the system. The property causes fear of introducing changes, and is usually a sign of tight coupling.


I tend to agree with the philosophy that a language should not require an IDE to be productive in.

With function signatures, I think it's particularly relevant for documentation as well. I should be able to look at a function signature in generated docs and know everything about what goes into and comes out of that function. For me the signature should be a complete contract, and changing code within a function body should not be able to change the signature.


Looking at the language ref, you can specify the return types if you want to.


This is not that helpful if you are working with someone else's codebase


Worst part of Ruby for me, I hate inferred returns in general.


I think you may be thinking of implicit returns, where the `return` keyword is not necessary. An inferred return is a separate feature where the return type is known by the compiler, but not stated explicitly by the programmer. (Note that the code in question uses both.)

Ruby, of course, technically has both as well. However, inferring a return type in a dynamically-typed language is probably less noteworthy ;)


I was going to pop in to say that. also going to add that I hate implicit things like this. messes with my brain, how hard is it to just add the return keyword? saving a few keystrokes hardly seems worth the increased cognitive cost to others.


In most languages that have implicit returns (that I’m aware of), the languages are also expression-oriented. For example, in Rust, if/else is actually an expression and you can use the result:

    let result = if foo > 5 {
        "Big foo"
    } else {
        "Small foo"
    };
Implicit returns are just an extension of this (it’s really just “semicolons create statements; if you don’t have a semicolon, that’s the final value of the block”). The explicit return is an actual statement that returns early.

IME the holistic design works pretty well, and I think you can glue together expressions much more naturally this way. The implicit return on itself would be much more annoying IMO.


“Implicit return” is basically a misnomer; there’s no language that I’m aware of that implicitly returns early. They’re all expression oriented and act like this.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: