aboutsummaryrefslogtreecommitdiff
path: root/notes/in_place_construction.txt
blob: ddc755c16333b88c56a1f4fbcaea7f1b8e7b7b82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

In-place construction
=====================

For example:

    a = get_a
    ...
    # if `a` is always the last reference, then this could
    # allocate the result "over" the previous allocation.
    # (note that this is tricky to do if the function also takes
    # the return value as a parameter, but in some cases it can be
    # done anyway).
    a = get_a

ABI
---

How should this work on the ABI level?
Maybe add a new parameter?

From this (source):

    func get_a
    returns
        Thing ret
    code
        ...
    end

To this (ABI pseudo code):

    func get_a
        ?Thing placement
    returns
        Thing ret
    code
        ...
    end

And with the edge case where the function takes the return value
as a parameter:

    func get_a
        aliased ?Thing placement
        aliased Thing existing
    return
        Thing ret
    code
        if placement == existing
            # implies placement<>none
            placement.a += 10
        elif placement <> none
            placement.a = existing.a + 10
        else
            ret = new
            ret.a = existing.a + 10
            return ret
        end
    end

Opaque and non-opaque types
---------------------------

This always works for non-opaque types. Those can even be allocated on the
stack (if small enough that there's no risk for eventual stack overflow).

For opaque types, it only works if there's an object that can be recycled.


Usages of in-place construction
-------------------------------

If objects are allowed to have variable length, then in-place construction
could be used for sub-arena allocation into an embedded slot type:

TreeNode:

    typeparam T

    ?TreeNode T left = none
    ?TreeNode T right = none


    embed T data


    constructor
        embed T data
    code
    end

    # TODO nicer getters?
    func get_data
    returns
        T data
    code
        return data
    end
    # maybe this:
    func get_data = data

TreeExample:

    func f
    code
        TreeNode Thing tree = new new
    end

Implementation idea:

* Have an internal function TreeNode__prealloc
* Take a allocation placement parameter in constructors
* Optionally take a size parameter (necessary for e.g. embedded arrays),
    - This would prevent variable-sized data structures though.

Pseudo-code:

    TreeNode<Thing> tree = TreeNode__prealloc()
    Thing_new(tree.data)
    TreeNode_new(tree)