Message Boards Message Boards


Create user-defined structured data type in WL?

Posted 1 month ago
9 Replies
3 Total Likes

I cannot find some sort of user defined structured data type like Record or Type in other languages. I always use nested list or associations instead of that, which is not really comfortabel. Is it true that I cannot define my data types at will?

As an example in, say, VBA I would write something like:

' --- User-defined Types
    x As Double
    y As Double
End Type
    p As T_POINT
    s As Double
End Type

' --- User-defined data
Dim myState As T_STATE

' --- Use such data types
Sub CB_init_Click()
    init myState
    With myState
        Range("s_px") = .p.x
        Range("s_py") = .p.y
        Range("s_s") = .s
    End With
End Sub

Sub init(state As T_STATE)
    With state
        .p.x = 1
        .p.y = 2
        .s = Rnd()
    End With
End Sub

In WL I would have to use lists, something like:

p = {1, 2};
state = {p, RandomReal[]};
Print["state: \t", state];
Print["state.p: \t", state[[1]], "\tstate.p.y: ", state[[1, 2]]];
Print["state.s: \t", state[[2]]];
state:  {{1,2},0.851364}
state.p:    {1,2} state.p.y: 2
state.s:    0.851364

Or associations, something like:

p = <|"x" -> 1, "y" -> 2|>;
state = <|"p" -> p, "s" -> RandomReal[]|>;
Print["state: \t", state];
Print["state.p: \t", state["p"], "\tstate.p.y: ", state["p"]["y"]];
Print["state.s: \t", state["s"]];
state:  <|p-><|x->1,y->2|>,s->0.198831|>
state.p:    <|x->1,y->2|> state.p.y: 2
state.s:    0.198831

Both are certainly fast, but not very readable (in particular the list-form).

And I cannot really force a variable assignment to a certain data type, i.e. a pattern. For example in the association-case I could define named patterns like:

Pattern[TPOINT, <|"x" -> _Number, "y" -> _Number|>];
Pattern[TSTATE, <|"p" -> _TPOINT, "s" -> _Number|>];

But how can I then force the assignments above to p and state to obey those patterns? Favourably at compiletime, not runtime?

9 Replies

Mathematica is a language for recognizing expressions by structure and rewriting them according to rules. This is very different from the sort of procedural languages you are familiar with. Something like:

a["state"] = 4

simply means "when you see a["state"], replace it with 4". You're not really "indexing" anything.

Posted 1 month ago

Hello Werner,

if I understood your post correctly, it contains basically two questions:

(1) how to make an expression in Mathematica type safe, so that incorrect types raise an error message

(2) how to create structures data types

Mathematica works more like an interpreter than a compiler, but supports compilation of functions. This can be employed to raise error messages in case of a type missmatch (which you already mentioned). Below is code (requires M12) that shows this for your examples:


First we define a function with excepts typed data, namely a list of two Real64.

tPointF = Function[
  Typed[list1, TypeSpecifier["PackedArray"]["Real64", 1]], list1]

Next the function is compiled:

tPointT = FunctionCompile[tPointF]

Now we instantiate this function with two arguments, the first one fits the spec, whereas the second arguments is a list of two integers:

{tPointT[{1.23, 4.56}], tPointT[{1, 4}]}

The same can be done for a function that accepts one Real64:

zahlF = Function[Typed[zahl, "Real64"], zahl];
zahlT = FunctionCompile[zahlF];

Next step is to build a structure like datatype. The closest I came up with is a dataset:

createDataInstance[list_, zahl_] := 
 Dataset[<|"p" -> tPointT[list], "z" -> zahlT[zahl]|>]

myDataInstance = createDataInstance[{1., 2.}, RandomReal[]]

Using a dataset you can access the data similar like from a struct:

{myDataInstance, myDataInstance["p"], myDataInstance["z"]}

And you can extract the raw data from it using Normal:

{myDataInstance // Normal, myDataInstance["p"] // Normal, 

Is this what you had in mind?

Posted 1 month ago

No, I do not refer to OOP, but much less. Just user-defined data types as they are in common in practically every classic programming language for about 50 years (Algol, Pascal, C, PL/1, Cobol, VB, Matlab, etc.).

Of course, I know about OOP (C++, Java, Smalltalk, etc.) and even how it can be more or less emulated in every 3rd-generation programming language. But this is not what I want to do with Wolfram Language.

I think associations, as described above, are the best approximations in WL. What is missing is compile-time checking of the data.

I mean you can just do this:

a["state"] = 4
a["test"] = 3

and then you can just query those:

If[a["state"]==4, Print["woohoo!"]]

where a is just a symbol.

But you can do the same with a being an Association.

Posted 1 month ago

Hmm, this is strange. I did not know that I can index any symbol by a string. Very similar to associations. But less useful. My example would now read:

p["x"] = 1; p["y"] = 2;
state["p"] = p; state["s"] = RandomReal[];
Print["state: \t", state];
Print["state.p: \t", state["p"], "\tstate.p.y: ", state["p"]["y"]];
Print["state.s: \t", state["s"]];
state:  state
state.p:    p state.p.y: 2
state.s:    0.428189

Note that for example state["p"] gives the expected value {1,2} if state and p are associations. But it just gives the name p in the case of symbols.

Anyway. For the moment I go ahead with associations.

Posted 1 month ago

Ja, thanks for the explanation. This is clear now.

Posted 1 month ago

There are new features Typed and TypeSpecifier in V12. Maybe this could be used for my purpose.

I did not have the time to elaborate on that feature. Looks like it is thought fo compiled function only.

Posted 1 month ago

Wow, thanks, Michael. This is what I had in mind. It's a bit complicated and not very readable. But it does what it should do.

BTW: That Mathematica is an interpreted, not compiled language is not really an argument against standard user-defined types. Many interpreted languages have this. For example Microsoft Visual Basic. See my first example in Excel VBA above.

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract