News for hackers. Stuff that matters.
[dead]
Re:My favorite Rust function by shhsshs on Saturday October 12, 2019 @11:10PM (#21238092)
> Enumerations

    type myEnum int
    const (
        someValue myEnum = iota
        anotherValue
        moreValues
    )
> Sum types

Consider thinking about the types in your sum type and what they have in common, and define an interface that they share.

> Recursive types

Not sure what you mean. This is valid Go:

    type tree struct {
        value int
        left *tree
        right *tree
    }
> Parametric polymorphism

Yes Go sucks in this area. `sort.Interface` is a good example of a workaround, but it isn’t ideal in any way.

> There is no this in GOLANG:

Is this not acceptable?

    var x interface{}
    json.Unmarshal([]byte(“[1,2,3]”), &x)
And if you don’t like that you get back a `[]interface{}` that happens to hold `int`s that you must type assert, just do it the better way:

    var x []int
    json.Unmarshal([]byte(“[1,2,3]”), &x)
Re:My favorite Rust function by crimsonalucard on Saturday October 12, 2019 @11:39PM (#21238207)
> Enumerations

- those are integers not enumerations. In Golang they have a type Bool which is either true or false. Can I define my own type using the same convention in GoLang? No. I can't. Ideally I want the ability to do this:

   type Bool = Enum {
      True
      False
   }
or

   type Tri = Enum {
      True
      False
      QuantumTrueFalseDuality
   } 
But in Golang I'm locked in with what the creators provided as primitive types. I can't go deeper. Rust you can.

> Sum types.

I don't think you know what a sum type is. This is what I mean by lack of knowledge. For sum type (A | B), A and B do not need to have a single thing in common and they do not need to share an interface. Think of a product type (A, B) as A and B and a sum type (A | B) as A or B.

The most glaring replacement of sum types in go are done with product types that contain errors from IO functions in GoLang. The Error type does not have anything in common with the Value it usually shadows and therefore both cannot be represented with an interface.

> Recursive types.

That's somewhat recursive. But that's a pointer. This works and is valid. Ideally though it shouldn't be a pointer but for efficiency during memory allocation this is a viable restriction. Recursive types only with pointer types.

> Parametric Polymorphism

I agree with you.

> Is this not acceptable?

No it is not acceptable. Interface is unusable until you make the type concrete with your asserts. Asserts are you executing a guess on a possible JSON permutation. In your second example you are guessing the type to be an array of INTs. What if that string was arriving over the wire as IO and you don't know what configuration it will be in? What if the typing was more complicated?

   jsonString = "[1,2,True,[1,2,\"hello\"]]"
or

   jsonString = randomJSONFromIO()
The assert also leaves an opening for a runtime error which is unacceptable.

imagine syntax like this:

   type JSON :: []JSON | Struct{string: JSON} | bool | int | string | null
   var x JSON = json.Unmarshal("[[1,2,True,[1,2,\"hello\"]],{}, null]")
JSON is a type represented using sums (|), products (Struct) and recursion (JSON). There is no possibility of run time errors here as you don't need to guess a specific permutation of JSON. You don't need to guess because such a type system can fully represent JSON. You see what is missing with go?
Re:My favorite Rust function by shhsshs on Wednesday October 23, 2019 @08:06AM (#21333692)
> Enumerations

I don't see the value in defining a custom underlying type for an enum. If it's for efficiency, sure. I've never had to use enums in a heavily performance-sensitive context so I don't personally relate to that.

> The assert also leaves an opening for a runtime error which is unacceptable.

You can handle errors gracefully.

    // default to 0
    maybeInt, _ := myValue.(int)

    maybeInt, ok := myValue.(int)
    if !ok {
      // do something else
    }
> imagine syntax like this:

In my opinion JSON with multiple types like that is poor design.

Regardless, even with sum types the programmer has to write code for most possible states each value could be in. You have the same capability in Go with type assertions.

    // Rust
    match myValue {
        int => ...,
        string => ...,
        // etc.
    }

    // Go
    switch myValue.(type) {
        case int:
            ...
        case string:
            ...
        // etc.
    }
Re:My favorite Rust function by crimsonalucard on Wednesday October 23, 2019 @10:03AM (#21334717)
This isn’t about personal opinion. This is about understanding the fundamental mathematics behind types. In type theory there are two fundamental composite types. Product types and sum types. Sum types are types that can be A or B or C. Product types can be A and B and C.

An example of a product type is any type that can hold multiple typed entities, whether that’s a list, array, structure or map.

An example of a sum type is polymorphism defined using inheritance. The children of a parent type are encoded into the type itself, but the type instantiated can only take the form of one of the children.

Note that my example for the sum type is isomorphic to a typed enum. It’s literally the same concept. Sum types and product types are mathematical opposites. Every language that has algebraic data types has this concept encoded into it. Go is one of the few typed languages that doesn’t have it.

Let’s get away from the mathematics and talk about practicality. Your example of the switch and pattern matching. Let’s say myValue is an int, a string or a float.

Let’s also say that when you are coding you miss checking for the float case and you add an extra invalid case where the code checks for Double? What happens in rust or go? In go nothing happens because go doesn’t truly know the underlying type so by doing this the code compiles and you have encoded a runtime error into the code.

For rust exhaustive type checking will catch both the missing handler and the invalid case. That’s right rust will know you have missing logic based off of the type. This is a powerful feature that is encoded into most languages that have algebraic data types.

Now let’s take the conversation back to math. The fundamentals. Have you ever thought about what an Int actually is? Looks like an enum doesn’t it?

   type int = 0 | 1 | 2 | 3 ...
If you really want to get deep an int is actually a recursive enumeration similar to json.

   type int = 0 | (int, 1) | (int, 2) | (int, 3) | ... (int, 9); 
So for example ints are instantiated like this..

   0 = 0,
   1 = (0, 1)
   2 = (0, 2)
   .
   .
   .
   12 = ((0, 1) 2)
   .
   .
   .
   456 = (((0, 4), 5), 6)
Operations like addition and multiplication are defined in terms of inductive mappings between enumerations.

This fundamentally what a type is. Any language missing the ability to define this is missing a mathematical primitive. It is incomplete. Go is a language that simply has an arbitrary enumeration (int) defined and the rest of the code needs to build off of it as there is no mechanism to define your own. Ints should be encoded as enumerations not the other way around.

Re:My favorite Rust function by HeyImAlex on Sunday October 13, 2019 @01:13AM (#21238504)
Isn’t that JSON example the same in python, javascript, and ruby?

Unmarshalling into an interface is really just a shitty enum; the number of permutations is finite. A type switch here is like a match but less type safe because it won’t check exhaustiveness of the branches.

Re:My favorite Rust function by crimsonalucard on Sunday October 13, 2019 @01:46AM (#21238589)
>Isn’t that JSON example the same in python, javascript, and ruby?

No. Python doesn't have type checking. That example is a made up syntax of golang if golang had all the correct type primitives.

In this example I am defining a type in the first line, similar to how you would define a struct in golang. Then using the type in the second line.

There is a bit of an error, but it's too late to edit it now. the Struct in the type line should be map[string]JSON.

>Unmarshalling into an interface is really just a shitty enum; the number of permutations is finite.

The permutations of JSON are infinite. In the real world there are APIs describing deeply hierarchical data that have unpredictable deeply nested data structures. If I had a random JSON string generator, it's not that straightforward how you would save that JSON to a correctly typed variable in a GO program.

Unmarshalling you will have to define a new type for every permutation. It makes more sense to traverse the data structure to find it's structure rather then take a wild guess.

Either way in golang that "guess" happens at runtime so it will spit out an error at runtime, while with sum types and match you are type safe before the program even runs.

Re:My favorite Rust function by HeyImAlex on Sunday October 13, 2019 @02:22AM (#21238713)
I mean... that’s the point I was making. Interface is just like using a dynamically typed language. So saying python can do this but golang can’t is wrong. They are effectively the same.

RE: Permutation, the unmarshalled value will only ever be float64, bool, string, interface[], or map[string]interface. The nested interfaces are recursively defined. It’s literally just like doing it in rust, except the compiler won’t do exhaustiveness checks for you.

Re:My favorite Rust function by crimsonalucard on Sunday October 13, 2019 @04:01AM (#21239133)
Hm. Ur right bad examples. The only advantage rust has then is more elegant syntax and safety for JSON. Ur also right about python and ruby. It is effectively the same.

Overall though the need for assert is a sign of a crippled type system.

Re:My favorite Rust function by speedplane on Sunday October 13, 2019 @04:10AM (#21239159)
> Overall though the need for assert is a sign of a crippled type system.

Given that most (if not all) new applications have to ingest data from third party systems and export outgoing data to other third party systems, the need for assertions and data validation is not going away, even in strongly typed systems.

JSON is becoming the de-facto data transfer format, and thus JSON input validation is necessary in both weekly and strongly typed systems. Assuming this JSON trend continues, we can predict stronger JSON type checking built directly into languages.

Re:My favorite Rust function by crimsonalucard on Sunday October 13, 2019 @11:37AM (#21240948)
Uh no. Type assertion is not always required. This is false. Also type assertion is not a good thing in a strongly typed language. This happens in Golang exactly because the go type system is flawed. It doesn’t need to happen.

There is a huge difference in guessing a type using assertions or writing handlers within the boundaries of a domain. Alex’s point that writing such code is effectively the same as rust because the amount of code is the same. However safety is lost. There is literally no point of having a type system in place when unmarshalling Json in go because you have no type safety. In go if you assert the wrong type or if your missing a required assert the error may be hidden and if it’s not hidden you can only see it during runtime. In rust there is no type assertion, only type checking, so such a program won’t even compile.

Re:My favorite Rust function by dullgiulio on Sunday October 13, 2019 @04:42AM (#21239268)
Those above are not integers but type that you have to explicitly cast integers to if you really want. Please don't make uninformed comments.
Re:My favorite Rust function by crimsonalucard on Sunday October 13, 2019 @11:41AM (#21240975)
I don’t understand what you are referring too. Why don’t you clarify, then we’ll see who is truly uninformed. I readily cop to my mistakes and errors. Will you?