Sum data type

From Rosetta Code
Revision as of 17:36, 25 June 2019 by rosettacode>Craigd (→‎{{header|Rust}}: added zkl header)
Sum data type is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Data Structure
This illustrates a data structure, a means of storing data within a program.

You may see other such structures in the Data Structures category.


Task

Create a sum data type:

A sum data type is a data structure used to hold a value that could take on several different, but fixed, types. Only one of the types can be in use at any one time.

Sum data types are considered an algebraic data type and are also known as tagged union, variant, variant record, choice type, discriminated union, disjoint union or coproduct.

Related task
See also




Go

Go doesn't natively support sum types, though it's not difficult to create one (albeit verbosely) as the following example shows.

Normally, the IPAddr type (and associated types/methods) would be placed in a separate package so its 'v' field couldn't be accessed directly by code outside that package. However here, for convenience, we place it in the 'main' package. <lang go>package main

import (

   "errors"
   "fmt"

)

type (

   IpAddr struct{ v interface{} }
   Ipv4   = [4]uint8
   Ipv6   = string

)

var zero = Ipv4{}

func NewIpAddr(v interface{}) (*IpAddr, error) {

   switch v.(type) {
   case Ipv4, Ipv6:
       return &IpAddr{v}, nil
   default:
       err := errors.New("Type of value must either be Ipv4 or Ipv6.")
       return nil, err
   }

}

func (ip *IpAddr) V4() (Ipv4, error) {

   switch ip.v.(type) {
   case Ipv4:
       return ip.v.(Ipv4), nil
   default:
       err := errors.New("IpAddr instance doesn't currently hold an Ipv4.")
       return zero, err
   }

}

func (ip *IpAddr) SetV4(v Ipv4) {

   ip.v = v

}

func (ip *IpAddr) V6() (Ipv6, error) {

   switch ip.v.(type) {
   case Ipv6:
       return ip.v.(Ipv6), nil
   default:
       err := errors.New("IpAddr instance doesn't currently hold an Ipv6.")
       return "", err
   }

}

func (ip *IpAddr) SetV6(v Ipv6) {

   ip.v = v

}

func check(err error) {

   if err != nil {
       fmt.Println(err)
   }

}

func main() {

   v4 := Ipv4{127, 0, 0, 1}
   ip, _ := NewIpAddr(v4)
   home, _ := ip.V4()
   fmt.Println(home)
   v6 := "::1"
   ip.SetV6(v6)
   loopback, _ := ip.V6()
   fmt.Println(loopback)
   _, err := ip.V4()
   check(err)
   rubbish := 6
   ip, err = NewIpAddr(rubbish)
   check(err)

}</lang>

Output:
[127 0 0 1]
::1
IpAddr instance doesn't currently hold an Ipv4.
Type of value must either be Ipv4 or Ipv6.

OCaml

<lang ocaml>type tree = Empty

         | Leaf of int
         | Node of tree * tree

let t1 = Node (Leaf 1, Node (Leaf 2, Leaf 3))</lang>

Rust

<lang rust>enum IpAddr {

   V4(u8, u8, u8, u8),
   V6(String),

}

let home = IpAddr::V4(127, 0, 0, 1);

let loopback = IpAddr::V6(String::from("::1"));</lang>

zkl

<lang zkl></lang>