20

We have all seen integer, floating point, string, and the occasional decimal type. What are some of the most strange or unique or useful types you have encountered, useful or not?

8
  • Hi user10008, welcome to Programmers.SE! Have you checked out our FAQ? Which of the six subjective guidelines do you think your question meets?
    – user8
    Commented Jan 25, 2011 at 0:04
  • 4
    Would anyone like to write the entry for Lisp?
    – Mark C
    Commented Jan 25, 2011 at 1:59
  • I thought it might have been a dupe, but only because my answer would have been a dupe, so I'll post a link and maybe you'll find some good answers: programmers.stackexchange.com/questions/724/… Commented Jan 25, 2011 at 18:58
  • @Mark: I tried, but types are probably one of the least interesting things about Lisp. Commented Jan 25, 2011 at 21:36
  • @LarryC I thought this was the perfect question for Lisp because of the all-pervasive use of lists ! The lists form the syntax tree and this allows you to write functions that do amazing things to your code, I gather. I'm learning Racket (previously PLT Scheme) now. Lisp is the only programming language I have been truly motivated and interested to learn.
    – Mark C
    Commented Jan 26, 2011 at 4:45

24 Answers 24

18

I'll be short:

Maybe a

in Haskell.

With this simple construct, the language solves the issue of crashes or NullPointerException, it neatly sidesteps the "One Million Mistake" of Tony Hoare :)

Frankly, an optional presence checked at compile-time ? It's dreamlike...

4
  • 1
    Or Option as it's called in many other programming languages.
    – Jonas
    Commented Sep 27, 2011 at 6:54
  • @Jonas: I must admit I don't like the Option name. Why not Optional! It may be because I am no native speaker, but Option does not convey the "optional" meaning to me. Commented Sep 27, 2011 at 7:01
  • The Maybe name is cute: "What do you have?" "Maybe an Int". However, the really neat bit is that it is both a functor and a monad which, in plain speak, means you get null-propagation for free. You never need to put null checks inside functions or in the middle of your code; you only ever need to check it at the very end of your code, if at all. Commented Jan 14, 2012 at 0:56
  • There's a Maybe monad for Ruby: lostechies.com/derickbailey/2010/10/10/the-maybe-monad-in-ruby Commented Jan 14, 2012 at 1:03
15

I am perennially fond of void *. It's probably a symptom of something deeply flawed in me.

5
  • 2
    Yes. I'm afraid that's exactly what it is. :) Oh, +1 for "interesting" rather than "unique". Objective-C obviously has void * and Pascal/Delphi have Pointer. Commented Jan 25, 2011 at 9:03
  • haha more of a non type, but you can't argue that it is not powerful
    – user10008
    Commented Jan 25, 2011 at 17:27
  • 15
    I just love the inherent pessimism it expresses: 'Can you see that thing over there?' 'Yes, what is it?', 'No idea.'
    – biziclop
    Commented Jan 25, 2011 at 19:11
  • I always thought it was funny that you can't declare a void but you can take the address of it. Seems to me that with struct s { int A; void B; int C ; } that the address of B should be the address of the crack between A and C. But no, not allowed. Commented Sep 27, 2011 at 9:43
  • That's why in pascal "pointer" is used to denote a generic pointer, and not confuse with "procedure".
    – umlcat
    Commented Sep 27, 2011 at 15:42
14

Lua has a built-in table that is most impressive. It has a built-in hashtable and a vector, and with the use of metatables can be the fundamental base for object-oriented programming in a procedural language.

Each index of a table can receive any of the basic language structures (number, boolean, string, function -yes, functions are types on lua -, and tables).

3
  • Note how Javascript is built in a very similar way, and Python is built on the very same foundation, as probably is Ruby.
    – 9000
    Commented Jan 25, 2011 at 0:31
  • I think this is also possible in Perl and PHP, yes? Commented Jan 25, 2011 at 5:43
  • There is a difference between the tables in lua and the hash containers in other languages. There is a subtle implementation difference in the way lua distributes hash values that makes its tables work in ways that are almost magical. I mostly program in python, and on occasion find that I'm using assumptions that don't hold, based on my expectations of the way tables work in lua. A specific example of this magic is that integers hash to themselves + 1. This means that integer keys are packed densly, and that +0.0 and -0.0 have the same hash (they are equal) Commented Jan 25, 2011 at 6:10
9

I'm surprised nobody has mentioned Monads or Algebraic Datatypes yet.

1
  • May be show us examples :)
    – nawfal
    Commented Oct 1, 2015 at 19:17
8

Lisp has two interesting types: t and nil. What's interesting about them is that everything is a t and nothing is a nil.

2
  • Are you serious? I did not know that.
    – Mark C
    Commented Jan 26, 2011 at 4:47
  • Is nil a t?
    – J D
    Commented Feb 10, 2018 at 20:06
6

SNOBOL: pattern (essentially a LL(1) parser tree, if I remember it correctly).

6

Fortran has common blocks; it's one of the least common data types in modern languages, or, rather an unusual way to efficiently share data.

Fortran 95 has interval types and built-in interval arithmetics.

The list would not be complete without monadic types found in Haskell. To understand them you need a bit of effort.

3
  • Ah, UniData/UniVerse DBs have common blocks in their internal language (UniBasic) too. Commented Jan 25, 2011 at 0:39
  • Is a common block a block of code that is used by different parts of the program?
    – Mark C
    Commented Jan 26, 2011 at 4:52
  • 1
    @MarkC IIRC its basically global data, but each function that accesses has to explicitly say it is going to at the top
    – jk.
    Commented Sep 27, 2011 at 8:32
5

Delphi has sets (see also), which I don't believe are implemented the same way in other languages.

This makes storing multi-variable attributes in databases a breeze :D

4

I suppose it's really only strange coming from programming on a classical architecture, but certainly one of the hardest types for me to wrap my head around at first was the quantum register, which shows up in QCL.

3

PL/SQL lets you declare variables of type my_table.some_column%type... I find that pretty damn useful.

And C# lets you declare objects as nullable or not, though I'm not sure that counts as a type.

2
  • 4
    But cursor%rowtype is even funnier: it's a dynamically-formed record type that reflects which columns the cursor's query returns.
    – 9000
    Commented Jan 25, 2011 at 0:36
  • .NET "Nullable" is actually a (generic) type in itself.
    – Konamiman
    Commented Sep 27, 2011 at 7:20
3

I had a soft spot in my heart for Euphoria's data types when I was younger

It is structured as thus:

Object
-> Atom
-> Sequence
  • Atom = A single numeric value
  • Sequence = A sequence of Objects

    -- examples of atoms:
    
    0
    98.6
    -1e6
    
    -- examples of sequences:
    
    {2, 3, 5, 7, 11, 13, 17, 19}
    {1, 2, {3, 3, 3}, 4, {5, {6}}}
    {{"jon", "smith"}, 52389, 97.25}
    {}                        -- the 0-element sequence
    

    See: The Ref Manual

Note: "jon" is actually a short hand way of writing the sequence of ASCII values. For example "ABCDEFG" is the same as {65, 66, 67, 68, 69, 70, 71}

3
  • 7
    This feels LISP-like... Commented Jan 25, 2011 at 5:43
  • The actual data types are the only bit. Commented Jan 25, 2011 at 7:13
  • 1
    @FrustratedWithForms Same, I thought, "Hey, he said, 'Atom'! This looks like (a) Lisp but with unnecessary dividers. :P
    – Mark C
    Commented Jan 26, 2011 at 4:54
3

Felix has anonymous sum types. The type is written like:

typedef il = int + long;

as it would be in theory. The values are ugly:

case 0 of il (1)
case 1 of il (2L)

except perhaps for a unit sum such as 3 = 1 + 1 + 1

case 0 of 3
case 1 of 3 

which unfortunately uses zero origin counting for "C compatibility". Anonymous sums are necessary for structurally typed algebraic types, for example:

(1 + T * li) as li

is a (singly linked) list of T. All other languages I know of required nominally typed sums, where both the type itself and the constructors must be given names.

The shorthand 3 used above is cute, the following is in the library:

typedef void = 0;
typedef unit = 1;
typedef bool = 2;

and this notation:

 T ^ 3

is an array of static length 3 .. the 3 is not an integer but a sum of 3 units. What a pity + is not associative :)

2

q/kdb+ has tables built-in. Since it's a programming language and column-oriented database in one, there's no need for LINQ or ORMs.

For example, can create a table like this (assignment is distinquished by : rather than = as in most languages):

people:([]name:`Joe`Amy`Sarah; age:17 15 18; GPA:3.5 3.8 3.33)

Now I can look at my table:

q)show people
name  age GPA 
--------------
Joe   17  3.5 
Amy   15  3.8 
Sarah 18  3.33

And I can query it:

q)select from people where GPA>3.4
name age GPA
------------
Joe  17  3.5
Amy  15  3.8
2

I found union's in C++ to be 'quirky' when I first heard about them. I still haven't hit a scenario where they're the obvious choice to implement.

3
  • 3
    Unions came from C. One good example is the zval struct in php. Commented Jan 25, 2011 at 7:12
  • 2
    I've used them in a Z80 emulator, to easily access the 16 bit registers as whole registers (HL, BC) and as 8-bit registers (H, L, B and C). This reflects how they're used in Z80 asm. Also in "variants", a class that can hold a value of different types (for example int/float) - not sure why I didn't use subclasses, but it made sense at the time :)
    – ggambetta
    Commented Jan 25, 2011 at 11:50
  • @ggambett: I have done exactly the same for my Z80 programs! Only that I have also added a bitfield to access individual flags in the F register.
    – Konamiman
    Commented Sep 27, 2011 at 7:21
2

I'm still trying to wrap my head around what a multi-parameter function becomes in F# and other functional languages. Basically int f(Foo, Bar) becomes func f(Foo)

That is the two parameter function that takes a Foo, and a Bar and returns an int is really a one parameter function that takes a Foo and returns a one parameter function that takes a bar and returns an int. But somehow you can call it with two parameters if you want. I wrote a post about it here

1
  • 8
    Rather, a function f(Foo, Bar) is the same as function f(Foo) that returns another function f'(Bar) which returns the value what f(Foo, Bar) would return. That is, if you fix the 'Foo' argument, but not 'Bar', you have a function that does not depend on 'Foo' but still depends on the 'Bar' argument. This is typical for functional languages; it's called 'currying'.
    – 9000
    Commented Jan 25, 2011 at 0:40
2

Regular Expressions:

They are extremely powerful yet compact objects.
Languages that have them built in have great ability to manipulate text (lets not hear the word parse they are not that good).

4
  • 2
    It is entirely possible to parse many simple grammars with regexes. For instance, it's relatively trivial to parse an ini file with a minimum of logic on top of a set of regexes. The mistake a lot of people make is trying to parse very complex grammars with it (ie. XML/HTML). Commented Jan 25, 2011 at 5:33
  • @MatthewSch NEW! How to parse HTML with regex!
    – Mark C
    Commented Jan 26, 2011 at 4:50
  • @Mark C: The top is answer is (with a record breaking 4320 up votes). You can't Commented Jan 26, 2011 at 5:37
  • Yes, that was for humor. It sprang to mind when I read Matthew's comment.
    – Mark C
    Commented Jan 26, 2011 at 5:56
2

A handful of languages in the functional family have a class of types known as Unity. The distinguishing feature of Unity types are that they contain no information, they are zero bit types. A unity type (in some variations) is also its only value, or (in most others) has only one value (that is not itself a type).

These are useful, though, because they are distinguished types. Since you can't implicitly convert from one unity type to another, you can put static type checking to work in a very efficient, and expressive way.

Unity is also the way most such languages describe Enums, by allowing a new type to be any of a defined set of other types, or to describe maybe types, values that may be either a value of a typical type (say, an integer), or have a value that represents no-value.

Some languages that don't employ the richness of user defined unity types still have unity in them, in some form or another. For instance, Python has at least three unity types, NoneType, NotImplementedType, and EllipsisType. It's interesting that the first two both mean something like "No value", but the third is used in complex values (specifically, slice expressions) to represent interesting special cases.

Other interesting examples of unity include NULL in sql and undefined in javascript, but not void in C or C++. void fails. Even though it describes a value of no information, but no actual value can be of type void.

1
  • I think you mean "unit type". Commented Jan 25, 2011 at 9:25
2

Ruby's symbol type is a bit unusual. It's essentially a string implementing the singleton pattern. Or something. So far, I've found the best uses for symbols are in tracking states and passing function names.

2
  • Also as keys to a map for O(1) key comparison.
    – Jeremy
    Commented Jan 25, 2011 at 19:11
  • Well, it's not really that unusual. Ruby inherited it from Smalltalk, which inherited it from Lisp. Scala also has it, I think. In fact, almost every language implementation (compiler or interpreter) has a symbol table internally, Lisp, Smalltalk and Ruby just expose it to the programmer. Commented Apr 13, 2011 at 23:46
1

COBOL. Essentially only two basic data types, strings and numbers, but you have to specify exactly how they're laid out in memory, e.g. PIC S9(5)V99 COMP-3.

4
  • I can beat that. BCPL has one data type - word; see en.wikipedia.org/wiki/BCPL
    – Stephen C
    Commented Jan 25, 2011 at 5:20
  • There are different types of numbers (COMP, COMP-1, COMP-2, COMP-3). Commented Jan 25, 2011 at 18:47
  • That sounds awful. Can you elaborate on what those details mean?
    – Mark C
    Commented Jan 26, 2011 at 4:51
  • S = signed, 9(5) = 5 digits, V = implicit decimal point, 99 = 2 more digits, COMP-3 = BCD + sign nybble.
    – dan04
    Commented Jan 26, 2011 at 5:28
1

Clipper had 'Code Blocks', which were similar to anonymous methods. They could be passed around and evaluated as needed, usually as a form of a callback. You'd often use them for things like performing calculations on the fly when presenting tables of data.

0

VHDL has physical types. A literal of such type includes both a value and a unit. You can define subunits as well. For instance, a predefined physical type is time:

type time is range <machine dependant> to <machine dependant> 
units
  fs;
  ps = 1000 fs;
  ns = 1000 ps;
  us = 1000 ns;
  Ms = 1000 us;
  sec = 1000 ms;
  min = 60 sec;
  hr = 60 min;
end units;

Together with operator overloading, you can define very interesting things.

0

Clojure is interesting because it has a meta-concept of "abstractions" that pervade the language. Examples:

  • Collections
  • Sequences (lazy and non-lazy)
  • Higher Order Functions
  • Multimethods
  • Protocols
  • Managed references
  • Macros
  • various others.....

To some extent, the abstractions take the "single responsibility principle" to the extreme. It's up to you to compose them to get the functionality that you want, but you can be extremely flexible about how you glue them together.

For example, if you want a class-based OOP system with inheritance, you could build one out of these core abstractions relatively quickly.

In practice, the abstractions themselves are designed in a way that multiple implementations are possible, e.g. through specific interfaces like clojure.lang.ISeq for sequences or clojure.lang.IFn for higher order functions.

There's an interesting video about this topic: The Art of Abstraction

0

If you want a language with a unique type then head for BCPL. This language only has one data type, the word, being a fixed number of bits for the language implementation.

0

Googles Go has a "Channel" type which is quite unique.

2
  • 1
    Channels aren't unique. Many languages have them. Felix had them 10 years before Google existed :) Ocaml had them 10 years before Felix existed.
    – Yttrill
    Commented Jan 13, 2012 at 20:13
  • And there was at least one other language which had channels before Ocaml existed. Still one of the least available types in programming languages.
    – Brainlag
    Commented Jan 14, 2012 at 11:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.