WILT: Go and Objects

A while ago I did the Ray Tracer Challenge in PHP. It was fun, and I built a teapot. Just sticking with a language I know is not getting the full experience of the book, so I tried redoing it in Rust. I found Rust quite difficult, it's code structures odd, and I just never got my head around modules. So I restarted using Go (on a good friend's suggestion) and found that much more my speed. I'm up to Chapter 5. It's tough going in some points but Go is a good language. What I'm enjoying:

  • Static typing. A thing is a thing, and you must specifically recast variables to change them, unlike PHP's take-what-you-give-me-I'll-deal-with-it
  • Enforced module structure. Add a library by creating a directory, naming a file in the directory the same, and name the package the same. Logical, fits together, compartmentalised.
  • Testing. Oh the testing in this is glorious. Make a file named [file]_test.go in the same directory as [file].go and fill it with your tests. Visual Studio Code's modules let me just click a test to run it instantly and get feedback, and running all tests tells me code coverage and highlights executed and skipped code in the editor. It's grand

Things I'm struggling with:

  • Looping references. Making a ray tracer, everything kinda talks to each other, so linking libraries in a circle causes Go to No. I've had to put all my shapey things in one Shape library
  • Static returns. Bleh. I want to return Nil if no result, or a false, and return the actual value if it succeeded. Go appears to have return Error as a separate parameter and check for true/ falseness there. Seems overkill
  • Classes
  • Lists

Ok, these last two are big ones. With the Intersects object, you return a list of intersections with a Ray. The intertsection has a T indicating where on the ray from origin the intersection happened, then an Object that was intersected with. Since this is for generic ray tracing, the object could be a Sphere, or a Plane, or a Triangle. But with Lists/arrays/dictionaries in Go they have a single type for their contents. Some Googling has a possible answer, I'm going with it.

  1. Create an interface

    1type Shape interface {
    2    Intersects(ray.Ray) Intersections
    3    Equals(Shape) bool
    4}
    
  2. Create instances of the class that inherit and reflect

    1type Sphere struct {
    2    common // Common holds an "Id" that's uniquely generated for comparison
    3}
    
  3. Build the rest of your class ensuring the definitions match. Since Sphere is reflecting Shape, you can replace Shape with Sphere in parameters

    1func (this *Sphere) Equals(shape Shape) bool {
    2	return true // Will be replaced with that "Id" comparison above
    3}
    
  4. Use the base class as the parameter to functions, or as the type in a array/dict/list, and it can be any of the instantiations of the base class

    1type Intersection struct {
    2    T      float64
    3    Object Shape
    4}
    5
    6func MakeIntersection(t float64, o Shape) Intersection {
    7    return Intersection{T: t, Object: o}
    8}
    

Seems to be working. I'd love any Go experts to give me pointers.