dgo

module
v0.4.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 21, 2020 License: Apache-2.0

README

dgo (Dynamic Go)

Dgo's main objectives are: Type Constraints, Immutability, Collections, Serialization, Encapsulation, Extendability, and Performance. It is designed to make working with dynamic values an effortless and type safe task.

Install

Dgo is a go module and if the Go version is < 1.13, go modules must be enabled. This is done by setting the environment variable GO111MODULE=on before an attempt is made to install:

export GO111MODULE=on
Using dgo as a library

To use dgo, first install the latest version of the library:

go get github.com/lyraproj/dgo

Next, include needed packages in your application. Pick what you need from the following packages:

import (
  "github.com/lyraproj/dgo/dgo"
  "github.com/lyraproj/dgo/typ"
  "github.com/lyraproj/dgo/tf"
  "github.com/lyraproj/dgo/vf"
)

Type Constraints

Dgo types versus Go's native types

Go is a typed language but the types are not very descriptive. It is for instance not possible to declare a type that corresponds only to a specific range of integers, a string that must confirm to a specific pattern. All such constraints must be expressed as code wherever a value of the type is assigned. In dgo a type describing a range of integers can be declared as 0..15 and a pattern constrained string can be declared as /^[a-z]+$/.

It is also not possible to declare type combinations such as a slice that can contain only integers or floats. If a value can be of more than one of go's native types, then it must be declared as an interface{} which corresponds to every possible value in the system. This means that a slice containing ints and floats must be declared as []interface{} wich is a declaration of a slice that may contain any type of value. In dgo, such a type can be declared as [](int|float). Other examples:

  • map[string](string|int) (string keyed map of string
  • []0..15 (slice of integers ranging from 0 - 15).
  • "red"|"green"|"blue" (enumeration of strings)
  • 2|8|10|16 (enumeration of integers)

Dgo is influenced by restrictive type constraint languages such as:

Language syntax

Dgo defines a type language of its own which is designed to be close to Go itself. A parser and a stringifier are provided for this syntax. New parsers and stringifiers can be added to support other syntaxes.

Type Assignability

As with go reflect, types can be compared for assignability. A type is assignable from another type if the other type is equally or more restricitive, e.g. the type int is assignable from the range 0..10 (and all other integer ranges). The type string is assignable from the pattern /abc/, the type "a"|"b"|"c" or any other type that restricts a string. A length constrained string[10,20] is assignable from string[12,17], etc.

Type Instance check

A type can be used to validate if a value is an instance of that type. The integer 3 is an instance of the range type 1..8, the string "abc" is an instance of the pattern type /b/, etc.

The type of a value

All values have a type that is backed by the value itself. The type will consider its value, and only that value, to be an instance of itself. E.g. string "hello" is represented by the type "hello". That type in turn is assignable to string, string[5], string[0,10], "hello"|"goodbye", but it is not assignable to string[0,4] or "hi"|"bye". In other words, the value type is assignable to another type if the value that it represents is an instance of that other type.

Collection types

The type of a collection is just a cast of the collection itself and hence, will change dynamically when the collection is modified.

Immutability

Non primitives in Go (array, slice, map, struct) are mutable and it's the programmers responsibility to ensure that access to such values are synchronized when they are accessed from multiple go routines.

Dgo guarantees that all values can be 100% immutable by exposing all values through interfaces and hiding the implementation, thus enabling concurrency safe coding without the need to synchronized use of shared resources using mutexes.

AnArray or a Map can be created as a mutable collection but can be made immutable by calling the method Freeze() or Copy(true) (argument true requests a frozen copy). Both calls are recursive and ensures that the collection and all its contained values are frozen. Freeze performs an in-place recursive freeze of all values while Copy will copy unfrozen objects before freezing them to ensure that the original and all its contained values are not frozen as a consequence of the call.

A frozen object can never be unfrozen. The only way to resume mutability is to do Copy(false) which returns a mutable copy.

Serialization

Support for JSON is built in to Dgo. YAML support is provided by the dgoyaml module which also provides a CLI validate parameter types. Support for gob is in the pipeline.

Transformations between dgo and cty is provided by the dgocty module

Transformations between dgo and pcore is provided by the pcore module

Encapsulation

It's often desirable to encapsulate common behavior of values in a way that relieves the programmer from trivial concerns. For instance:

  • In Go, you cannot define a generic behavior for equality comparison. It's either == or reflect.DeepEqual() and both have limitations. == cannot compare slices or structs containing slices. The DeepEqual method compares all fields of a struct, exported and unexported. Dgo solves this by letting all values implement the Equals() method. This method is then used throughout the Dgo framework.
  • Go has no concept of a hash code. Keys in hashes may only be values that are considered comparable on Go. Dgo solves this by letting all values implement the HashCode() method. The hash code can be used for several purposes, including map keys and computing unique sets of values.
  • Since Go has generic value (besides the interface{}, it provides no way to specify generic natural ordering. Dgo provides a Comparable interface.

Extendability

The functionality of the Dgo basic types is exposed through interfaces to enable the type/value system to be expanded.

Performance

Dgo is designed with performance in mind. The Map implementation is, although it's generic, actually faster than a map[string]interface{}. It is a lot faster than a map[interface{}]interface{} required if you want to use dynamic keyes with Go. Nevertheless, the Dgo Map can use any value as a key, even arrays, maps, and types.

The dgo.Value implementation for primitives like Bool, Integer, and Float are just redefined Go types, and as such, they consume the same amount of memory and reuses the same logic i.e.:

type integer int64 // implements dgo.Integer
type float float64 // implements dgo.Float
type boolean bool  // implements dgo.Boolean

The dgo.String is different because it caches the hash code once it has been computed. A string is stored as:

type hstring struct {
  s string
  h int
}

How to get involved

We value your opinion very much. Please don't hesitate to reach out. Opinions, ideas, and contributions are more than welcome. Ping us on the Puppet Cloudnative Slack, create an issue, or file a PR.

Pipeline

  • dgo annotations for go struct members, e.g.
    type Input struct {
      Variables map[string]interface{} `dgo:"map[string]dgo"`
      Parameters map[string]interface{} `dgo:"map[string]{name: string[1], type: dgo, required?: bool}"`
    }
    
  • Go gob support to enable full binary exchange of values and types.
  • Distributed type aliases (aliases using URI reference)
  • Type extension, i.e. how a type such as a map with explicit associations can be extended by another type.

Directories

Path Synopsis
Package dgo contains all interfaces for the dgo types and values.
Package dgo contains all interfaces for the dgo types and values.
Package require contains the test helper functions for easy testing of assignability, instance of, equality, and panic assertions.
Package require contains the test helper functions for easy testing of assignability, instance of, equality, and panic assertions.
dgocty module
Package internal provides stuff internal to Dgo.
Package internal provides stuff internal to Dgo.
Package loader contains the Dgo loader infrastructure
Package loader contains the Dgo loader infrastructure
Package parser contains the Dgo parser and lexer
Package parser contains the Dgo parser and lexer
Package streamer contains the logic to convert dgo values into sequences of data and vice versa.
Package streamer contains the logic to convert dgo values into sequences of data and vice versa.
pcore
Package pcore contains the parser and lexer for the Puppet Type syntax.
Package pcore contains the parser and lexer for the Puppet Type syntax.
Package stringer provides the functions needed to create the string representation from a Type
Package stringer provides the functions needed to create the string representation from a Type
Package tf (Type Factory) contains the factory methods for creating dgo Types
Package tf (Type Factory) contains the factory methods for creating dgo Types
Package typ contains the static dgo types such as typ.String and typ.Any
Package typ contains the static dgo types such as typ.String and typ.Any
Package util contains Dgo utility functions
Package util contains Dgo utility functions
Package vf (Value Factory) contains all factory methods for creating values
Package vf (Value Factory) contains all factory methods for creating values

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL