Monthly Archives: July 2016

Andl.Net – making progress

Working surprisingly well. As purely a query language, it has:

  • Equals, subset, distinct
  • Where
  • Select (combines Rename, Project, Extend)
  • Set ops: union, minus, intersect, symdiff
  • Join and Antijoin
  • Order by (for export purposes)
  • Skip Take

The code looks like this:

      class TT1 : NdlTuple<TT1> {
      public string A2;
      public int A1;
      public decimal A3;
      public static TT1[] R1() {
        return new TT1[] {
          new TT1 { A1 = 42, A2 = "hello", A3 = 1.2m },
          new TT1 { A1 = 42, A2 = "world", A3 = 1.2m },
        };
      }
      public static NdlRelation<TT1> NDR_1() {
        return new NdlRelation<TT1>(R1());
      }
    }

    var v1 = TT1.NDR_1();
    var v2 = v1.Where(t => t.A1 == 42);
    var v3 = v2.Select(t => new TT2 { A1 = t.A1, A2 = "constant", A3 = t.A3 });

I’m making heavy use of NUnit and finding plenty of bugs. No updates yet; no data import; no aggregation; no while/recursion; no ordered queries. But it all seems surprisingly possible, even without a lot of help from the compiler. And much easier than writing compilers.

Leave a Comment

Filed under Andl.Net

Andl.Net – the type system

To recap: this is about attempting to reproduce the essential capabiities of Andl (based on TTM/D) as a set of extensions to a standard OO language. I am using C#, but my comments should apply equally to Java, C++, Rust, Dlang, Go, etc.

In my opinion the TTM/D type system can be substantially reproduced as follows.

  1. Scalar types: the requirements are satisfied by any type that is immutable and provides value semantics. In practice this means a class in which:
  • All members are (recursively) scalar, tuple or relation types
  • Members can only be set to a value at construction time
  • Operator ‘=’ implements equality of value
  • The hash value depends only on the value (therefore is constant)
  1. Tuple types: the requirements are satisfied by a type that is immutable and has value semantics, and also:
  • All members are scalar types or (recursively) tuple types
  • Operator ‘=’ implements equality of value by member name (only if same heading)
  • The hash value depends only on the value (therefore is constant)
  • A value can be created by member-wise copy of another tuple type (only if same heading)
  1. Relation types: the requirements are satisfied by a type that:
  • Can provide an enumerator over tuple types for others to use
  • All operations on relations are then implemented by enumerating streams of tuples (pipelining).
  1. Relvar: an object of relational type with the additional feature that:
  • It can accept an enumeration over tuple types and apply it to a persistence store.

Tuple types are the core of the system. In the absence of compiler support, every tuple type consumed or emitted by any relational operator has to be individually declared, but the common functionality comes from inheriting a base class and related interfaces.

Relation types are interesting. A lengthy sequence of operations of the Relational Algebra is just a set of chained functions calls and enumerators. It does not in fact cause any processing of data until a caller either (a) retrieves data to be sent elsewhere or (b) commits a transaction. A relvar is a relation type from which an enumerator can be obtained and which accepts updates. It is not a collection, just an adapter to someone else’s collection.

I have a crude but working implementation (and I have learned a lot about C# generics). Still hard to tell whether it leads anywhere, but I should be able to hook it up to the Andl database backend and then we’ll see. An Sql implementation can then generate Sql and enumerate the result set instead of the raw data (Andl does that).

 

Leave a Comment

Filed under Andl.Net

Andl.Net — is it possible?

This the first of a series of thoughts about implementing a language capability similar to Andl (which is in turn based on The Third Manifestoon C# for use by programs written in C# (as against Andl which has entirely its own type system). The intention is not to focus on C# specifics, but issues relevant to any strongly-typed language, with perhaps an OO focus.

The Relational Algebra can be seen as dealing with streams of tuples, where

  • A tuple value is assumed to be a native type (plain old object/record/class/struct) already existing in the language
  • The input stream source will create the values; two streams of the same tuple type might have different native types.
  • The output stream is also a native type, not necessarily the same as any input. Client software needs familiar data sources.
  • The native type for those values cannot be relied upon to provide value semantics, or anything else required by the implementation.

Consider the implementation of a simple algorithm such as Union:

  • There are three types (left input, right input, output) which should be the same tuple type but may be different native types
  • Removing duplicates can be done with a hash set, which in turn requires a hashing function that depends only on tuple type (not native type).

Possibilities:

  1. If native types are used in implementation algorithms, they need to be augmented post hoc with additional operations (equality, hashing, cloning). That’s hard.
  2. If the implementation uses its own augmented native types then every input tuple has to be copied, but outputs can be consumed directly by clients. Dynamically creating native types is hard too.
  3. The implementation could convert all tuple data into dicts (hashes) or arrays of values; but this requires copy/conversion on both input and output. This is probably the easiest (but not where I started out).

In C# much of the implementation requires reflection. The Andl implementation is similar to (3).

Leave a Comment

Filed under Andl.Net, Pondering