Most languages are privileged. In python you can't define your own calling convention or add your own flow control.
If the language wasn't privileged, then it would't be a language.
>you can't pass a slice of concrete types conforming to an >interface into a function expecting a slice of interfaces.
Interface and concrete types are different sizes, so doing this requires an allocate. The language chooses not to hide this as it would be different from how all other kinds of slices work.
> Makes it difficult to find out why your program crashed
> because the information you need has been cut off by the
> terminal!
This is a problem with your terminal. Getting a terminal that has a bigger buffer is a good idea, logging to a file is also a good idea. It would be weird to have the thing that happened first be at the end of the stack trace.
>If you want to change whether an entity is public/private, >you have to replace all occurrences.
This is a rare thing to do and you get the advantage of knowing the visibility of a method or variable as you read it. Code is read more often than it's written, so they optimise for readability.
>You can't use custom types for the key of a map. To get >around this, you have to use maps of maps.
The built in map covers most people's needs. If your needs differ then people have written external packages that implement a hash map. Every additional feature is a burden on anyone that doesn't use it.
> You can't select over multiple io.Readers without starting > a goroutine for each one.
You can't select{} on io.Readers because the io package isn't part of the language. But you can certainly write a package that uses the OS's select() syscalls to wait on any number of file descriptors(which would block the goroutine and the thread it's running on as expected).
Yep. But goroutines are cheap. Also, how do you select over an arbitrary type?
>> The language is privileged Most languages are privileged.
> In python you can't define your own calling convention or add your own flow control. If the language wasn't privileged, then it would't be a language.
I'll clarify. I don't think languages should be privileged in regard to types.
>> you can't pass a slice of concrete types conforming to an interface into a function expecting a slice of interfaces.
> Interface and concrete types are different sizes, so doing this requires an allocate. The language chooses not to hide this as it would be different from how all other kinds of slices work.
Whether it requires an allocation or not, it's an annoyance. This is just an example of behavior that is counterintuitive w.r.t interfaces.
>> Makes it difficult to find out why your program crashed because the information you need has been cut off by the terminal!
> This is a problem with your terminal. Getting a terminal that has a bigger buffer is a good idea, logging to a file is also a good idea. It would be weird to have the thing that happened first be at the end of the stack trace.
I've now set the terminal buffer to unlimited, but it's annoying to have to scroll back though thousands of stack traces.
>> If you want to change whether an entity is public/private, you have to replace all occurrences.
> This is a rare thing to do and you get the advantage of knowing the visibility of a method or variable as you read it. Code is read more often than it's written, so they optimise for readability.
I see your point here, but I'm not saying I agree.
>> You can't use custom types for the key of a map. To get around this, you have to use maps of maps.
> The built in map covers most people's needs. If your needs differ then people have written external packages that implement a hash map. Every additional feature is a burden on anyone that doesn't use it.
I certainly don't agree with "Every additional feature is a burden on anyone that doesn't use it", more like "Every additional feature is a missed opportunity for a bad headache".
>> You can't select over multiple io.Readers without starting a goroutine for each one.
> You can't select{} on io.Readers because the io package isn't part of the language. But you can certainly write a package that uses the OS's select() syscalls to wait on any number of file descriptors(which would block the goroutine and the thread it's running on as expected). Yep. But goroutines are cheap. Also, how do you select over an arbitrary type?
It's possible. You could have an interface that has a function that sets a callback that is called when data is available and in this callback you could then write to a channel. When you read from the channel, you'll get messages from each of the io.Readers. Goroutines are cheap, but I'm not convinced they are cheap enough.
> Whether it requires an allocation or not, it's an annoyance. This is just an example of behavior that is counterintuitive w.r.t interfaces.
If I had a 1GB []byte and passed it in to a function taking an []interface{}. I think it would be really counterintuitive that the function call would allocate 16GB of memory. While passing it to a function taking a []byte would allocate no memory at all. You can't avoid this allocation.
It's been considered that it might be nice to be able to convert between slices of different interfaces and this might happen, but it's not going to happen for slices of types for the reason above.
The special case of auto-converting a type to an interface on assignment is a bit weird and creates endless confusion for new people coming from different language as it makes Go's interfaces look like they are the same as Java or C++'s. But once you understand it, then it makes sense.
In Java an Interface and an Object are very similar, they both have a set of virtual methods and interfaces just verify that the type you're passing in has the expected set of virtual methods to implement the interface. Converting an array of Java Objects to an array of Java interfaces doesn't require anything at runtime.
In Go, a type and an interface are very different, a type has static methods and an interface has virtual methods.
> Converting an array of Java Objects to an array of Java interfaces doesn't require anything at runtime.
It potentially costs every time you put something into the array - Java arrays are covariant. Either a runtime check is needed, or the JIT compiler will have to create a proof that any particular array access is to a consistently typed array.
I think I'm right in saying that haskell does what you'd expect when you have a list of some typeclass. The difference is that Go has opted to use RTTI, whereas haskell does it a compile time. So, it's not impossible to do well.
> I don't think languages should be privileged in regard to types.
C++, relatively speaking, is not "privileged" with regard to types, but that lack of privilege is bought with great pain, particularly in exception safety mixing with copy constructors. The lack of semantic guarantees when overriding operators - like assuring the unsuspecting library user that x += y does something similar to x = x + y - can also be a genuine problem. Java evaded the whole thing for quite justifiable reasons, IMO, and C# implements operator overloads in relatively specific ways to avoid some of these problems - and still doesn't let you have copy constructors, assignment operators, or destructors on value types.
By baking in certain assumptions about types into the language, the commonality across all code written in the language is increased, and the costs of documentation and communication at independently developed library boundaries is reduced. There are also other benefits; with baked-in knowledge, the language may support value literals for specific types in the lexer and parser. Doing this in a non-"privileged" way would require macros or compiler plugins, which are themselves undesirable for a whole set of other reasons.
Most languages are privileged. In python you can't define your own calling convention or add your own flow control. If the language wasn't privileged, then it would't be a language.
>you can't pass a slice of concrete types conforming to an >interface into a function expecting a slice of interfaces.
Interface and concrete types are different sizes, so doing this requires an allocate. The language chooses not to hide this as it would be different from how all other kinds of slices work.
> Makes it difficult to find out why your program crashed > because the information you need has been cut off by the > terminal!
This is a problem with your terminal. Getting a terminal that has a bigger buffer is a good idea, logging to a file is also a good idea. It would be weird to have the thing that happened first be at the end of the stack trace.
>If you want to change whether an entity is public/private, >you have to replace all occurrences.
This is a rare thing to do and you get the advantage of knowing the visibility of a method or variable as you read it. Code is read more often than it's written, so they optimise for readability.
>You can't use custom types for the key of a map. To get >around this, you have to use maps of maps.
The built in map covers most people's needs. If your needs differ then people have written external packages that implement a hash map. Every additional feature is a burden on anyone that doesn't use it.
> You can't select over multiple io.Readers without starting > a goroutine for each one.
You can't select{} on io.Readers because the io package isn't part of the language. But you can certainly write a package that uses the OS's select() syscalls to wait on any number of file descriptors(which would block the goroutine and the thread it's running on as expected). Yep. But goroutines are cheap. Also, how do you select over an arbitrary type?