Next Article in Journal
Determinants of the Intention to Use Digital Technology
Previous Article in Journal
Vehicle Exhaust Estimation Using YOLOv7 and Support Vector Regression with Image Features
 
 
Font Type:
Arial Georgia Verdana
Font Size:
Aa Aa Aa
Line Spacing:
Column Width:
Background:
Article

Intentionally Fusing Direct Manipulations into SVG Programs

by
Tao Zan
1,
Xing Zhang
2,
Xiao He
3,* and
Zhenjiang Hu
2
1
School of Mathematics and Information Engineering, Longyan University, Longyan 364012, China
2
School of Computer Science, Peking University, Beijing 100871, China
3
School of Computer and Communication Engineering, University of Science and Technology of Beijing, Beijing 100083, China
*
Author to whom correspondence should be addressed.
Information 2025, 16(3), 169; https://doi.org/10.3390/info16030169
Submission received: 7 January 2025 / Revised: 19 February 2025 / Accepted: 20 February 2025 / Published: 24 February 2025
(This article belongs to the Topic Software Engineering and Applications)

Abstract

:
Bidirectional live programming is a programming paradigm that enhances the developer experience by allowing direct modifications to the output, with changes instantly reflected back to the source program. Existing operation-based approaches allow modifying the constant values and expressions of programs, while they lack control over modifications originating from multiple updatable locations. To control the updatability of the source program, our approach introduces non-updatable expressions, which guide the fusion of updates to the intended locations. The correctness properties, GetPut and WeakPutGet, ensure output consistency. We have implemented a prototype, FuseSVG, and tested it with 14 nontrivial SVG-drawing benchmarks, demonstrating the effectiveness of our approach.

1. Introduction

Programming can be mentally taxing as it requires us to envision the execution of code during the editing process. Live programming [1,2,3], however, alleviates this strain by continuously re-executing the program during the editing phase, thereby establishing a seamless feedback loop between the programmer and the program. Bidirectional live programming [4] further enhances the developer’s experience by providing a distinctive feature, known as direct manipulations [5], which allows for direct modifications to the output. These changes are instantaneously reflected back to the source program, guaranteeing that the updated program can reproduce the manipulated output.
Sketch-n-Sketch [4,6,7,8] is a bidirectional live programming system that allows direct manipulation on the output, eventually causing the system to substitute old constants in the program with new ones.
The code in Figure 1 creates a rectangle with a width that is twice its height (expressed as mult 2 h in the code). If a programmer attempts to widen the rectangle horizontally while maintaining the height, they would be unsuccessful. This is because any change to the rectangle’s width in the SVG results in an update to the rectangle’s height in the program, due to the default update policy that modifies the right operand of the expression mult 2 h. Sketch-n-Sketch provides a freeze operation that uses ! to mark a constant, indicating that it cannot be modified. If the constant value of height 100 is marked with !, the rectangle becomes un-stretchable. Furthermore, if the programmer wants to change the expression from mult 2 h to mult 2 h + 50 by directly manipulating the output, thereby establishing a new correlation between width and height, this is unachievable as the system only permits updates to constants. To summarize, Sketch-n-Sketch allows for the modification of constants, yet it constrains the adjustment of expressions, such as the correlation between width and height.
FuseDM [9] fuses direct manipulations into source program by propagating them to constants whenever possible. In order to satisfy the correctness that the execution of the updated program yields the same manipulated output, sometimes direct manipulations will be embedded into a “proper position”.
Figure 2 depicts the same rectangle. If the programmer stretches the rectangle horizontally, the expression h*2, which represents the width of the rectangle, is updated to h*2+dh, where dh represents the displacement value, and the height h remains unchanged. Although FuseDM conveys the intention of updating the expression, it fails to express the intention of maintaining the relationship between width and height by adjusting the width. This is particularly important when drawing in SVG, as numerous relationships between SVG elements must be preserved.
In general, we propose an approach that sits between Sketch-n-Sketch and FuseDM, which is capable of preserving the relationships between SVG elements during manipulation, while also facilitating program updates. These updates encompass more than just changes to constant values; they also involve modifications to expressions. We developed FuseSVG with the following features: (1) We introduce a const keyword that can be used to designate an expression as non-changeable. This guides the fusion of manipulation, ensuring that marked expressions are not updated during propagation to prevent unintended changes. (2) The correctness is guaranteed by the GETPUT and WeakPUTGET properties. Since the relation is stored in the program, fusion followed by execution of updated program ensures that elements in SVG are consistent according to the relation. Moreover, the WeakPUTGET guarantees that updates are only reflected in related expressions.
The program shown on the left of Figure 3 conveys the intent that the value of the height variable h, and the expression that serves as the left operand of the binary expression h*2, are immutable. Consequently, any manipulation of the width will result in changes to the ratio value 2. If we further designate h*2 as const, as shown on the right of Figure 3, any manipulation of the width will lead to the transformation of the entire binary expression from const(h*2) to an updated expression const(h*2)+dh, where dh denotes the displacement value. This kind of transformation is not feasible in Sketch-n-Sketch.
FuseSVG builds upon our previous work, FuseDM [9], while FuseDM laid the foundation for bidirectional live programming with an operation-based approach for fusing updates into the source program, FuseSVG refines and enhances this framework by addressing key limitations identified during the development of FuseDM. Specifically, FuseSVG introduces improvements in the handling of update propagation, correctness in positioning updates, and user-intended relationships within the program. These extensions make FuseSVG a more robust and flexible approach, offering finer control over program updates while maintaining consistency.
In summary, our contributions are as follows:
  • We introduce a manipulation-directed programming approach where manipulations represent changes on the SVG. These changes are fused into programs to construct a desired program. Furthermore, a const marker is utilized to guide the propagation and fusion of the manipulation in the intended location.
  • We design both the forward evaluation and the backward fusion semantics to preserve manipulations. We have proven that the language semantics satisfy the GetPut and WeakPutGet properties to guarantee correctness, thereby ensuing the validity of our approach.
  • We have implemented a prototype, FuseSVG, that supports manipulation-directed programming for SVG. It has been tested with 14 nontrivial benchmark examples to demonstrate the effectiveness of our approach.

2. A Core Language DF

We initially describe the syntax of the core language DF, which stands for the functional language F with Deltas. The DF language is designed as a minimal core language for expressing key concepts of our system, particularly the manipulation of program deltas and the structured application of updates. It formalizes how delta values are handled, enabling precise reasoning about how changes propagate through a program. The purpose of DF is to provide an abstract environment in which the logic of program updates can be clearly modeled and analyzed. Next, we present its formal semantics and provide inference rules that determine whether a given expression is modifiable, which are used during the manipulation propagation process.

2.1. Syntax of DF

In Figure 4, we outline the core functional language, DF, designed for crafting source programs. Basic expressions are composed of constants c, variables x, abstractions λ p . e , and applications e 1 e 2 . It also includes binary expressions, case expressions, and fix e , which is used to described recursive functions. Constructors include tuple constructions ( e 1 , e 2 ) and list constructions e 1 : : e 2 . The const keyword is introduced, which can be used to designate an expression as non-changeable (const e). Consequently, it includes a special expression e d v that retains the delta for the expression and a special value c d v that stores updates on the constant c, which are vital for demonstrating the correctness of our approach.
Constants encompass numbers n, Booleans b, strings s, and empty lists []. Values are made up of constants with deltas c dv , tuples ( v 1 , v 2 ) , list constructions v 1 : : v 2 , and function closures ( E , E b , λ p . e ) . The environment E is responsible for mapping variables to their corresponding values v, while the environment E b maps variables to Boolean values b v . b v represents a special Boolean value that includes true , false , a tuple of b v , and a special value ( E , E b , λ p . e ) , which is internally used for lambda expressions. Basic delta operations consist of i d , replacement (repl c ), composition ( dv 1 dv 2 ), plus delta ( + Δ atom ) that augment a given expression’s value, delete that signifies an element’s removal from the list, insert that indicates an element’s addition to the list, and an extra function closure used exclusively during computation. The subscript Δ is employed to differentiate the notations of the same operators in the arithmetic expression.
Example 1. 
A list of simple examples.
λ x . ( x , x ) 5 + Δ 10 An application with a constant value marked with a delta value . 5 + Δ 10 + 5 A binary expression whose left operand is a delta expression . ( const 5 , 5 + Δ 10 ) The first element of the tuple is not modifiable since it is marked by const . 5 + Δ 10 : : [ ] The first element of the list is a delta expression . 5 delete : : [ ] The first element of the list is deleted through manipulation . 5 insert : : [ ] The first element of the list is newly inserted through manipulation .
Example 2. 
Suppose the programmer stretches the rectangle horizontally by 10; the program defined in Figure 3 will be updated to the following one.
main = let h = const 100 in [ rect 0 182 70 ( const h ) 2 + Δ 0 . 1 h ] .
Note that a program augmented with deltas acts as an intermediate representation, which is crucial to our approach and will be explained in detail later. Delta values can be seen as a form of lifting, where updates (represented as deltas) are encapsulated within a computational context and applied to the source program, similar to how applicative functors apply functions to wrapped values. Specifically, delta values are combined and propagated through program expressions, preserving the program’s original structure and intent, much like how applicative functors combine computations in a functional context. However, all deltas are ultimately eliminated in the final program. The resulting program derived from Example 2 is shown below:
main = let h = const 100 in [ rect 0 182 70 ( const h ) 2.1 h ] .

2.2. Semantics of DF

This section describes the semantics of DF as shown in Figure 5. While most of the evaluation rules are quite straightforward, we only explain those rules that involve the delta or const marker. Evaluating a const-marked expression is equivalent to directly evaluating the expression itself. When evaluating an expression with a delta denoted as e d v , the expression e is first evaluated to a value v, resulting in a value v d v . We impose a restriction on binary expressions e 1 + e 2 and e 1 e 2 such that the delta d v can only occur on one side. This does not reduce the expressiveness of our language, as the delta only occurs on one side during update propagation in our setting.
Example 3. 
The evaluation result of the program in Example 2 is as follows, where the width value is set to 200, augmented with a delta of + Δ 10 :
[ rect [ 0 , 182 , 70 , 200 + Δ 10 , 100 ] ]

2.3. Updatability of Expression

When an expression is marked with const, the syntactic structure of the expression is not modifiable; however, the value of the expression may be subject to change if variables are present within the expression. To ascertain whether the computed value of an expression is updatable, we establish a set of inference rules. The const inference rules are outlined in Figure 6. If an expression is inferred as true , it signifies that the expression is not updatable. Conversely, if it is inferred as false , it implies that the expression is updatable.
As depicted in Figure 6, E signifies an environment for variables bound to their respective values, while E b represents a set containing variables bound to b v . For a given expression e, we infer it as b v to ascertain the updatability of the expression. Nearly every expression has two rules: one marked with const, and one without. If a constant is marked with const, it is inferred as true . In the absence of the const keyword, it is inferred as false . If the expression is inferred as false , then the const-marked expression is also inferred as false . The updatability of a variable depends on whether it is marked with the const keyword and the binding of the variable x in E b . However, if a variable x lacks the const keyword, it will invariably be inferred as false , indicating that the expression x is modifiable. For a lambda expression, we create a tuple that encapsulates E, E b , and the lambda expression λ p . e , which is utilized in lambda application. For a binary expression marked with const, we initially infer the Boolean value of the left and right operands when marked with the const keyword. The computation of b v 1 b v 2 is straightforward. Given that b v 1 and b v 2 can only be true or false , the result is true if both b v 1 and b v 2 is true , otherwise, it is false . If it lacks the const keyword, we directly return false . For a case expression, pattern p j is matched with b v 0 to construct E m b , which is subsequently used for evaluating e j . When a tuple is marked with const, we infer e 1 and e 2 when marked with const. The const inference rules for lists are the same as for tuples. When an expression contains delta, it will always be inferred as false if it is not marked by const. Otherwise, the delta should be i d and the result is the same as evaluating e.
Example 4. 
Given a lambda application, the environment E contains a variable y, and in the environment E b , the variable y is bound to true , then the inferred result is true .
{ y 1 i d } , { y true } ( const λ x . x ) ( const y ) true
Example 5. 
Given a binary expression, the environment E contains variables x and y, and in the environment E b , the variable x is bound to true , while the variable y is bound to false . Even if the binary expression is marked by const, it is inferred as false since y is inferred as false .
{ x 1 i d , y 2 i d } , { x true , y false } const ( x + y ) false

3. A Direct Manipulation Language DM

We begin by introducing the syntax of the direct manipulation language DM, followed by a description of its semantics in detail.

3.1. Syntax of DM

The syntax of DM is outlined in Figure 7. The symbol d v is used to denote a delta, which is capable of expressing a variety of direct manipulations. It is important to note that the same notation is employed in Figure 4. In the core language, DF, the symbol d v signifies the basic deltas that can be incorporated into the source program. The identity delta, id, leaves the output unaffected, while the replacement delta, repl  aexp , substitutes the output value with the computed value from aexp . The composition of two deltas, represented as dv 1 Δ dv 2 , signifies the manipulation of dv 1 on the output, followed by dv 2 . The addition delta, + Δ atom , appends the computed value from atom to the output.
The delta list constructor fabricates a list of deltas, dv 1 : : Δ dv 2 , that operates on a list. The list deletion delta, delete n, eliminates the nth element in the list, while the list insertion delta, insert n atom , introduces the computed value from atom as the nth element. The list modification delta, modify  n dv , updates the nth element by dv , and the list folding of delta, dfold, is analogous to foldl in Haskell. derive is a function, defined using the core language DF, that accepts the current accumulator, acc (an atomic expression), as input and derives a new accumulator, acc . In addition, it computes the arguments to be applied by the function todelta , which computes a delta for each list element being recursively processed. The binding operation, denoted as intro x by select into dv , introduces a new variable x, extracts a sub-value from the output value using the selector select , and then binds the variable x to that sub-value. The variable x is subsequently utilized in dv . The selector select is designed to extract a specific value from a data structure. It includes the identity selector id, and composition selectors with projectors comprised of head, tail, fst, and snd. The atomic expression atom encompasses constants c, variables x, tuples, and lists. The arithmetic expression aexp incorporates atomic expressions atom , additions aexp 1 + aexp 2 , multiplications aexp 1 aexp 2 , and so forth.
Example 6 
(Transforming a Rectangle into a Square). Consider a canvas with one rectangle, whose width is 200, and height is 100.
[ rect 182 ( 70 , 70 ) 200 100 ]
The operation to turn the rectangle into a square is written as follows: It first extracts the rectangle’s width using the selector head nth 3 id and assigns it to the newly introduced variable w. Then, it modifies the rectangle’s h with w.
intro w by ( head nth 3 id ) into ( modify 4 ( repl w ) )
Example 7 
(Turn Two Rectangles Horizontally Attached). Consider a canvas with two rectangles spread horizontally, but not attached. The operation to direct the second rectangle to attach to the first rectangle horizontally is written as follows: It extracts the first rectangle’s x and width using the selector head nth 2 fst id and head nth 3 id , and assigns it to the newly introduced variables x and w, respectively. Then, it modifies the second rectangle’s x with x + w .
intro x by ( head nth 2 fst id ) into intro w by ( head nth 3 id ) into modify 1 ( repl x + w , i d )

3.2. Semantics of Language DM

The semantics of DM  are defined in Figure 8. The judgment dv v v indicates that “applying a delta dv to the value v results in v ”. The definition of values v, which includes constants with delta, tuples, and lists, is provided in Figure 4.
The D-Id rule asserts that the identity id leaves the value v unchanged. The D-Repl rule introduces a new value, denoted as v , derived from the arithmetic expression aexp . It is important to note that the original value v is not directly replaced by v . Instead, the change is recorded as a delta. eval is an auxiliary function that evaluates arithmetic expressions into values. The D-Com rule states that the composition dv 2 dv 1 is applied to v, resulting in a delta value that stores the composed deltas. The D-Add rule states that, when applying + Δ atom to a numerical value n, the value v computed from eval ( atom ) is not directly applied to the value n, but is stored in a delta value. The D-Tuple rule states that, when applying the tuple delta ( dv 1 , dv 2 ) Δ to the tuple value ( v 1 , v 2 ) , v 1 (resp. v 2 ) is transformed by dv 1 (resp. dv 2 ) and becomes v 1 (resp. v 2 ). The D-Cons rule operates similarly to D-Tuple.
The application rules for deletion, insertion, and modification apply to list values. The D-Ins-1 rule states that when applying insert n atom to a list construction v 1 : : v 2 and n is larger than zero, v 2 is transformed by insert ( n 1 ) atom and becomes v 2 . The D-Ins-2 rule states that when n is zero, the computed value v 1 marked with delta insert is inserted at the front of the list v 2 . The rules for deletion and modification follow a similar pattern. The D-Fold rule applies deltas to each element from left to right. With the recursion logic(i.e., derive ) and the delta generation (i.e., todelta ), acc is an atomic expression denoting an accumulator, usually the list index. Let us use an example to show how the rule D-Fold works. The D-Binding rule is utilized for creating bindings from elements in the output. It initially introduces a new variable, denoted as x, to represent the value selected from an existing set using the s e l e c t function. The semantics of these selectors are elaborated in Figure 9. Subsequently, this selected value x is used to evaluate the change d v . This mechanism is employed in various applications such as defining alignment, joining points, and applying a format brush.
Example 8. 
Consider a sequence of rectangles on the canvas. The following operation sets all the rectangles’ widths to 100. The command modify 3 ( repl 100 ) changes a specific rectangle’s width to 100. The dfold function iterates over a sequence of rectangles from left to right.
dfold ( λ i . ( 0 , i + 1 ) ) ( λ x . modify 3 ( repl 100 ) ) 0
Example 9. 
The operation below sets the first rectangle’s width to 20, the second rectangle’s width to 40, and so on. Initially, i is set to 1, and the variable d i s is bound to 20. After one iteration, i is updated to 2, and the value of d i s becomes 40.
dfold ( λ i . ( i 20 , i + 1 ) ) ( λ d i s . repl 3 d i s ) 1

4. Fusing Delta into the Program

We first introduce the well-behavedness properties, followed by an example to illustrate how fusion operates. Subsequently, we present the primary fusion algorithms that fuse delta into program. Particularly, when program expressions are marked with const, the fusion rules become more intricate.

4.1. Well-Behavedness

Our system incorporates a fundamental bidirectional transformation mechanism, which comprises the standard evaluation (get function) and the fusion (putback function). These components maintain consistency between source programs and their outputs by satisfying the GetPut law and the WeakPutGet law.
Lemma 1 
(GetPut). If E e v , then id E e E e .
The GetPut law (stability) states that if we obtain an output from a program and perform no direct manipulation, the program must remain unchanged. This is straightforward because we default the delta modification to be the identity function (id), which keeps the same source program.
Lemma 2 
(WeakPutGet). If E e v , dv v v , and dv E e E e , E e v dv , then dv E e E e .
The WeakPutGet law (soundness) is more critical. It states that when a delta is fused into a program, even if the output of executing the modified program differs, by collecting the changes and fusing them again into the original program, we should obtain the same modified program.
Theorem 1. 
If a program satisfies the GetPut law and the WeakPutGet law, then the program is well behaved.
We need to emphasize that we use the WeakPutGet law instead of the PutGet law. The PutGet law is more restrictive, such that the output of executing the modified program is equal to the output generated by applying that delta to the original output. We relax it by allowing the updated outputs to change, which is important for reconstructing the correct relations in the output.

4.2. Fusion Example

Figure 10a depicts the fusion of a delta + Δ 2 , which adds 2 to the output of a program. The fusion involves a depth-first traversal of the program’s structure, as illustrated in Figure 10b (where let-bindings are represented as function applications). The green lines, labeled with numbers, indicate the path of the propagation. Once the timesExp node is reached, the traversal proceeds to the left branch, and the delta transforms into + Δ 1 . Ultimately, the delta is fused with the constant value 1 at the node highlighted in yellow. The final program is shown in the bottom of Figure 10a.
If we carefully analyze the propagation steps, it becomes apparent that there are other reasonable points for updating, rather than solely the “deepest” one. For instance, consider updating function definitions of plus or times. Since there are binary operations, we have the flexibility to update either operand. To address this, we introduce the const marker to indicate which parts we prefer to keep unchanged. For example, if we wish to preserve value of the let binding of the variable a and aim to update the plus function, we can mark the binding of a and the application times a as unmodifiable using const. The revised and updated program is presented as shown in Figure 11.

4.3. Fusion Rules

Fusion rules are the core mechanisms that propagate deltas across the main program structure. The key idea is to propagate the delta back to variables or sub-expressions using variable bindings (environment). Given a delta dv , under value environment E, and Boolean environment E b , update expression e to e , and update the value environment to E . The fusion rules are depicted in Figure 12 and Figure 13.
  • Constants. There are two rules for constant values. If a constant value is marked by the const keyword, it remains immutable (since the inference rule will always yield to true for a constant marked by the const keyword, only id is allowed). If the constant value c is not marked by the const keyword, it can be updated to c dv , as demonstrated in P-Con2. Note that we do not directly compute the result of applying dv to value c, but preserve the delta, which is important for proving the WeakPutGet law.
  • Variable Expressions. There are four rules for variable expressions based on whether the variable expression x is marked by the const keyword and whether the bound value for the variable is modifiable. It is crucial to differentiate between the variable expression x and the variable binding for x. The first rule P-Var1 states that if the bound value for the variable is not modifiable and the variable expression is marked by const, then only the delta id is permitted. The second rule P-Var2 states that if the bound value for the variable is not modifiable, but the variable expression is modifiable, then modify the expression to x dv . The third rule P-Var3 states that if the bound value for the variable is modifiable, and the variable expression is marked by const, then the variable x in the environment E is bound to a new delta dv 1 dv that composes dv 1 with the original delta dv . The last rule P-Var4 states that if the bound value for the variable is modifiable, and the variable expression is not marked by const, then despite the fact that updating the variable expression (as in P-Var2) or the variable binding (as in P-Var3) is reasonable, updating the variable, which yields a result identical to P-Var3, is the preferred approach. The last rule P-Var4 is the same as the P-Var defined in FuseDM [9].
  • Lambda Abstractions. The rule P-Lam1 states that, when applying the closure ( E , E b , const λ p . e ) , the program E , E b const λ p . e becomes E , E b const λ p . e . Since the lambda abstraction is marked by the const keyword, the body of the lambda abstraction (e) cannot be modified; only the bindings of the variables in the environment are updated. The lambda abstraction in P-Lam2 is not marked by the const keyword, and the fusion can be decomposed into two updates: replacing the function body with e and the environment with the updated one E .
  • Function Applications. The rule P-App1 states that, if the inference result of the application is true, the application is not modifiable. The rule P-App2 states that, if the inference result of expression e 2 is true, then only e 1 can be updated. When fusing delta d v to e f , even though there exists a possibility to update x, the fusion algorithm will refrain from updating x. We first evaluate e 1 to a lambda closure, a tuple of an environment E f , and a lambda abstraction λ x . e f . For simplicity, we assume only variable patterns in the lambda abstraction. Under the binding of variable x to v 2 , which is computed from e 2 and environment E f , we update the expression e f and environment E f to e f and E f , respectively. And finally, we use the updated expression e f and environment E f to update expression e 1 to e 1 , and environment E to E 1 . The rule P-App3 is a bit complicated, since both e 1 and e 2 can be updated, thus they may encounter conflicts. A merge operation is defined for resolving conflicts. The intuitive idea is explained by the example “fusing ( + Δ 2 , + Δ 3 ) Δ into the program ( , { a 0 id } , { a false } ) ( λ x . ( x , a ) ) a ” in Table 1.
The operator E 1 e 1 e 2 E 2 in Step 7 first merges variable bindings obtained from fusion of e 1 and e 2 , and then embeds inconsistent deltas into e 1 (resp. e 2 ) to obtain e 1 (resp. e 2 ), which is formally defined in Section 4.4. The final program is as follows, which evaluates to ( 2 , 3 ) .
( { a 0 id } , { a false } ) ( λ x . ( x , a + 3 ) ) ( a + 2 ) :
  • Case Expressions. The rule P-Case1 states that, if the inference result of the case expression is true, the expression is not modifiable. The rule P-Case2 states that, if the inference result of e 0 is true, then only the matched case branch expression e j is updated. The rule P-Case3 first applies the delta dv to the selected branch e j , resulting in the updated e j and E m . Then, it collects the delta from E m for e 0 , and subsequently fuses it into e 0 . Finally, the merge operator is used to resolve any conflicts.
  • Binary Expressions. The rule P-C-Oplus1 states that if a binary expression marked with const is inferred as true, then the expression is not modifiable. The rule P-C-Oplus2 states that updating a const marked binary expression is the same as updating the binary expression with each operand marked by const. The rule P-Oplus1 states that if both e 1 and e 2 are inferred as true, then update the entire binary expression with dv . The rule P-Oplus2 states that if e 1 is inferred as true and e 2 is inferred as false, then update the right operand e 2 by a computed delta d v v 1 . The rule P-Oplus3 updates e 1 instead. The rule P-Oplus4 states that, if both e 1 and e 2 are inferred as false, then it chooses to update e 1 , but a merge operation is needed to resolve conflicts. How to apply deltas to binary expressions varies in different deployments; we give potential heuristic rule (P-Oplus4) for applying deltas to left operands. Other strategies include modifying the right operands, which can be achieved by marking the left operand with const.
  • Tuples. The rule P-C-Tuple states that updating a const marked tuple is the same as updating each element marked by const. The rule P-Tuple states that one must update e 1 with d v 1 and e 2 with d v 2 . Since e 1 and e 2 may share variables, then a conflict-resolving operation is needed. The rule P-C-List (resp. P-List) is similar to the rule P-C-Tuple (resp. P-Tuple).

4.4. Merge Operation

Intuitively, the merge operator E 1 e 1 e 2 E 2 compares two structurally equivalent environments using the comparing operator × e 1 e 2 and then embeds conflicting bindings into sub-expressions using the embedding operator ⊙. The merge operator and the comparing operator are the same as the definition in FuseDM, except the definition of embedding operator.
Definition 1 
(Merge Operator). The merge operator E 1 e 1 e 2 E 2 reconciles conflicts of variable bindings as follows. ( E M , e 1 , e 2 ) = E 1 e 1 e 2 E 2 holds if
( E M , E 1 I , E 2 I ) = E 1 e 1 × e 2 E 2 , e 1 = E 1 I e 1 , and e 2 = E 2 I e 2 .
Definition 2 
(Comparing Operator). The comparing operator × e 1 e 2 compares two environments E 1 and E 2 and returns the successfully merged part E M and two inconsistent parts ( E 1 I and E 2 I ).
( E 1 , x v dv 1 ) e 1 × E b e 2 ( E 2 , x v dv 2 ) = ( ( E M , x v dv 1 ) , E 1 I , E 2 I ) if dv 1 = dv 2 ( ( E M , x v dv 1 ) , E 1 I , E 2 I ) if x fv ( e 2 ) ( ( E M , x v dv 2 ) , E 1 I , E 2 I ) if x fv ( e 1 ) ( ( E M , x v dv ) , ( E 1 I , x v dv 1 ) , ( E 2 I , x v dv 2 ) ) otherwise where ( dv , dv 1 , dv 2 ) = dv 1 prefix dv 2 where ( E M , E 1 I , E 2 I ) = E 1 e 1 × E b e 2 E 2
Definition 3 
(Embedding Operator). The embedding operator E I e embeds deltas bound in the mapping E I around free variables in e, denoted by
( E I , x v dv ) e = E I e [ x x dv ] ,
where the “ [ x x dv ] ” operator replaces the free occurrences of the variable x in e with x dv .
The embedding operator introduces deltas at the variable expression x, by substituting x with x dv to encapsulate the delta dv at the variable expression x. This approach differs from the mechanism employed in FuseDM [9]. However, when the program with deltas is evaluated to a program without deltas, the same embedding mechanism as described in FuseDM is utilized.

4.5. Well-Behavedness

The well-behavedness (Theorem 1) properties includes the GetPut law and the WeakPutGet law. The GetPut law is straightforward because when the direct manipulation is the identity id, it then keeps the same source program as it is. Proving the well-behavedness is essentially the same as verifying the WeakPutGet law. We give a sketch of the proof for the WeakPutGet law.
Proof. 
By induction on the fusion derivation below, we show the P-Con2, P-Var3, and P-App3 three cases as representatives:
  • The P-Con2 case:
      dv E , E b c E , E b c dv
    (a)
    According to P-Con2, the updated program is E , E b c dv .
    (b)
    By E-dv, E c dv c id dv .
    (c)
    The delta is id dv .
    (d)
    By P-Con2, id dv E , E b c E , E b c id dv .
    (e)
    Since id dv is the same as dv , E , E b c id dv is the same as E , E b c dv , which is the goal.
  • The P-Var3 case:
    E b ( x ) = false E ( x ) = v i d dv E , E b const x E [ x v dv id ] , E b const x
    (a)
    According to P-Var3, the updated program is the same as the original one, but the environment changes, E [ x v dv id ] , E b const x .
    (b)
    By E-Const, and E-Var, E [ x v dv id ] , E b const x v dv id .
    (c)
    The delta is dv id .
    (d)
    By P-Var3, dv id E , E b const x E [ x v dv id id ] , E b const x .
    (e)
    Since dv id id is the same as dv id , E [ x v dv id id ] , E b const x is the same as E [ x v dv id ] , E b const x , which is the goal.
  • The P-App3 case:
    E , E b e 2 e false E e 2 v 2 E e 1 ( E f , λ x . e f ) dv E f { x v 2 id } , E b { x false } e f E f { x v 2 dv 2 id } , E b { x false } e f ( E f , λ x . e f ) E , E b e 1 E 1 , E b e 1 dv 2 E , E b e 2 E 2 , E b e 2 ( E , e 1 , e 2 ) = E 1 e 1 E b e 2 E 2 dv E , E b e 1 e 2 E , E b e 1 e 2
    (a)
    According to P-, dv 2 v 2 v 2 .
    (b)
    By the induction hypothesis, E f { x v 2 dv 2 id } , E b { x false } e f v dv , E 1 , E b e 1 ( E f , λ x . e f ) , and E 2 , E b e 2 v 2 dv 2 .
    (c)
    By Lemma 4, E , E b e 1 ( E f , λ x . e f ) and E , E b e 2 v 2 dv 2 .
    (d)
    By (c) and Lemma 3, E f , x v 2 dv 2 id e f v dv .
    (e)
    By E-App, E , E b e 1 e 2 v dv .
    (f)
    By the induction hypothesis, dv E f { x v 2 id } , E b { x false } e f E f { x v 2 dv 2 id , E b { x false } e f } , dv 2 E , E b e 2 E 2 , E b e 2 .
    (g)
    According to definition, ( E f , λ x . e f ) E , E b e 1 E 1 , E b e 1 and ( E , e 1 , e 2 ) = E 1 e 1 E b e 2 E 2 , the updated program is E , E b e 1 e 2 , which is the goal.
   □
Definition 4 
(Equivalent Environment). E 1 and E 2 are equivalent (denoted E 1 E 2 ) if they are structurally equivalent and x E 1 , E 1 x v , and E 2 x v .
Lemma 3. 
If E 1 E 2 and E 1 e v , then E 2 e v .
Lemma 4 
(Merge Equivalency). If ( E , e 1 , e 2 ) = E 1 e 1 E b e 2 E 2 . E 0 , E 0 E 1 e 1 v implies E 0 E e 1 v .
Since Lemmas 3 and 4 are straightforward, we omit the details here.

5. Evaluation

The evaluation aims to analyze the expressiveness of the language to cover the scenario of SVG design. In addition, we present two typical benchmark examples in detail to show how an SVG graphic is constructed.

5.1. Expressiveness

FuseSVG introduces the const keyword, enabling users to mark expression to narrow down the appropriate location from multiple options, ensure certain constants in the program remain unaltered, and preserve relationships between SVG elements within the program. To illustrate the expressiveness of FuseSVG (FuseSVG is available at https://github.com/zanlyun/FuseDMI, accessed on 19 February 2025), we have replicated 14 benchmark examples and conducted an analysis from these three perspectives, as shown in Figure 14. All of these examples originate from FuseDM [9]. The results are summarized in Table 2. The term ‘Multiple update choice’ refers to situations where there are several possible places for making updates, such as the left or right operand of a binary operation. ‘Immutability for a single value’ suggests that the programmer intends to set certain constant values as non-updatable, like the x and y coordinates of a rectangle or the center of an ellipse. The ‘Number of relations’ corresponds to the count of relation expressions defined in the program. For instance, the width of a rectangle being twice its height ( 2 h ) is considered a relation.
Based on our analysis of the 14 benchmark examples, all examples encounter the problem of selecting suitable sub-expressions for updating when fusing deltas into the program. All examples necessitate the setting of certain constant values as non-updatable. For example, in the Precision Floor Plan example, there are three relations: the y coordinate of the second rectangle is identical to that of the first rectangle; the x coordinate of the second rectangle should be the sum of the first rectangle’s x coordinate and its width w; and both rectangles share the same height h. Relation expressions are defined across all examples and can be viewed as an important property in SVG design, emphasizing the importance of defining the invariance of relations in the source program.
Now, let us perform a detailed comparison between FuseDM and FuseSVG using the Precision Floor Plan Example. Listings 1 and 2 show the actual code for FuseDM and FuseSVG, respectively, which generates the output SVG shown in Figure 14(1). From a code perspective, compared to FuseDM, FuseSVG introduces const markers to specify that certain relations should be preserved, ensuring that certain expressions cannot be updated.
Listing 1. Precision Floor Plan Example in FuseDM.
main =
let rect1_x=175 in
let rect1_y=239 in
let rect1_width=60 in
let rect1_height=106 in
[
  rect[0,219,rect1_x,rect1_y,rect1_width,rect1_height],
  rect[0,30,rect1_x+rect1_width,rect1_y,rect1_width*2,rect1_height]
];
Listing 2. Precision Floor Plan Example in FuseSVG.
main =
let rect1_x=175 in
let rect1_y=239 in
let rect1_width=60 in
let rect1_height=106 in
{
 rect{0,219,const rect1_x,rect1_y,rect1_width,rect1_height},
 rect{0,30,const(rect1_x+rect1_width),rect1_y,const rect1_width*2,rect1_height}
};
When generating the SVG, we have a specific intent: Suppose the left-hand rectangle is rect1, and the right-hand one is rect2. For instance, rect2’s width is defined as twice rect1’s width (rect1_width * 2), and rect2 adheres to rect1, where rect2’s x is rect1’s x plus rect1_width, and rect2’s y is the same as rect1’s y.
Next, we perform three update operations on both FuseDM and FuseSVG, as shown in Figure 15. First, if we shrink rect2’s width by 16, FuseDM modifies rect2’s width expression to ( rect 1 _ width 8 ) 2 , which breaks the intended relationship. However, in FuseSVG, this update proportionally adjusts rect1’s width, preserving the relationship by shrinking it from 60 to 52.
Similarly, if we shrink rect1’s width by 13, the expression for rect1_width becomes rect 1 _ width 13 . In FuseDM, this breaks the relationship where rect2’s width is always twice rect1’s width. However, in FuseSVG, the width of rect2 is proportionally adjusted, preserving the intended relationship between the two rectangles by updating rect1_width to 47.
Finally, when we move rect2 horizontally by +10, FuseDM updates the expression rect 1 _ x + rect 1 _ width to ( rect 1 _ x + 10 ) + rect 1 _ width , breaking the alignment. In contrast, FuseSVG updates rect1_x directly, ensuring that the relative positioning of the rectangles is preserved. If we further want to keep rect1_x stable, we can mark rect1_x as const, ensuring that only rect1_width is updated.
In summary, FuseDM propagates updates to constants whenever possible while guaranteeing the PutGet property. However, this can sometimes lead to situations where relationships between elements are broken during updates, particularly when elements are interdependent or when updates occur in unintended locations. On the other hand, FuseSVG introduces more sophisticated mechanisms, such as using the const keyword for immutability, which helps preserve these relationships while still allowing for flexible updates. This ensures that changes to one element do not unintentionally disrupt the overall structure of the program.

5.2. Case Study

Let us use two benchmark examples to show how an SVG graphic is constructed step-by-step.
Battery Example: Initially, the canvas is empty, and the program assigns an empty list ([]) to a main variable. To draw a battery, we first draw a rectangle as shown in Figure 16a. This action automatically generates a piece of program, as shown on the right side, which is a main function that contains a list with the rectangle we just drew. The number 120 represents the color of the rectangle, while 119 and 146 are the x and y coordinates of the rectangle, respectively. The values 178 and 76 represent the width and height of the rectangle, respectively. By using direct manipulation, we eliminate the need to write the definition of the rectangle, especially the actual value. Sketching on the canvas is more intuitive than writing code. Subsequently, we draw another rectangle adjacent to the first one, as illustrated in Figure 16b. This action generates a delta, which is then fused into the program.
Although we placed the second rectangle next to the first one, the generated code does not inherently reflect this intention. The x value of the second rectangle (296) is very close to the sum of the x value and the width of the first rectangle (297). Therefore, we can refactor the code to establish relations by (1) abstracting values as variables and (2) constructing relations and marking them as non-modifiable with the const keyword. The final result is presented in Figure 16c. Now, regardless of whether we move or resize the first or second rectangle, the relations are consistently preserved.
Balance Scale Example: Figure 17 outlines the steps to construct a balanced scale (for more details, please refer to the video at the provided URL https://youtu.be/ImoOpGfubBw, accessed on 19 February 2025). After drawing the vertical red line in the second step, it is not possible to verify if the line is truly vertical just by looking at the SVG. Therefore, we need to check the code and adjust the y value to ensure it is truly vertical. Next, a refactoring step is needed to establish the relationship between the ellipse created in the first step and the vertical line. In fact, after each drawing step, a refactoring step is necessary to build the relationships, particularly the addition of the const marker, to the generated code. The construction of the balanced scale involves 20 steps and results in 26 lines of code. Since the relationships are well defined and marked as non-modifiable, any movement of an element in the figure will lead to changes in related elements.

6. Related Work

6.1. Bidirectional Transformations

Bidirectional transformations [10] serve as a mechanism for maintaining consistency between a source and a corresponding view, which is derived from that source. The programming language community has conducted extensive research on bidirectional transformations [11,12,13]. Existing approaches to bidirectional transformations have primarily focused on transformations over a variety of structured data [14]. This includes lists [15], trees [11,16,17], graphs [18,19], and relational databases [20]. Matsuda et al. [21] proposed FliPpr, a system designed to derive parsers from pretty-printers. None of the existing approaches permit modifications to the transformation program itself. In other words, updates to the view must remain within the scope of the forward transformation. However, our work, FuseSVG, supports updating the program to a new one. Cheney et al. [22] discussed the principle of least change for bidirectional transformations. They posited that a bidirectional transformation should only make changes to the artifact that are strictly necessary, which is a principle that can guide the design of backward transformations, but it does not allow for the updating of the bidirectional program.

6.2. Ambiguity and Updatability

Sketch-n-Sketch [4] employs heuristics to resolve ambiguities and introduces an approach based on trace-based program synthesis. This method tracks the origin of constants within the program and establishes value-trace equations with the manipulated output. These equations are subsequently solved using a constraint solver. As mentioned by the author:“Our approach utilizes heuristics to automatically resolve ambiguities, aiming to achieve a balance between interactivity and predictability.” For instance, consider the value-trace equation n = ( + x 0 ( l 0 s e p ) ) . This equation can be solved by arbitrarily altering the value of either x 0 or s e p .
Bidirectional Evaluation [7], Bidirectional Preview [23], and BiOOP [24], typically, introduce a backward update evaluation that propagates the updated output value to program constants by retracing the forward evaluation steps. Sketch-n-Sketch [6] provides semi-automated SVG programming via direct manipulation, and it is developed to further provide full output-directed programming for SVG [8]. During which, a freeze annotation, written !, is introduced to tell Sketch-n-Sketch not to change those constants marked by ! when shapes are moved on the canvas. The freeze operator is formally defined in the LITTLELEO language [7]. For a given expression marked by freeze ( f r e e z e e ), evaluation of this expression is the same as evaluating e, but for updating; if expression e evaluates to v, then only v can be propagated back, which means the value of the expression cannot be changed.
The motivation for introducing the keyword const differs from that of the freeze operation. While the freeze operation prohibits the changing of the value computed from the expression, our const keyword restricts the modification of the expression syntactically; however, the value can still be changed.
Let us assume that the output of the Sketch-n-Sketch program on the left, shown in Listing 3, represents the value of h. This output value is immutable, as the expression used to calculate h is marked with a freeze annotation(!). In contrast, within our system, FuseSVG, the const keyword is used to keep the expression 2*w static, while allowing for the update of the width w. The program is shown in Listing 4. The design goal of const is used to keep the form of the expression unchanged, which is useful for keeping the relation between two or more variables. The freeze totally prohibits any update to the variable in the expression. When const operates on constant values, it also does not allow modification of the constant value expression, which is, in fact the same as the freeze operation in Sketch-n-Sketch.
Listing 3. Sketch-n-Sketch.
        w = 50                
        h = !(2*w)
Listing 4. FuseSVG.
        w = 50                
        h = const (2*w)
FuseDM [9] adopts an operation-based approach that propagates deltas. This method can modify not only constant literals in programs but also alter program structures by integrating direct manipulations into the ‘proper position’. FuseDM has the same ambiguity issue as the state-based approaches. The application rules for fusing delta into addition expression A-Add and multiplication expression A-Mul defaults to update the left operand. Our work FuseSVG extends FuseDM by providing a const keyword, to describe user intention of which part in the program shall not be modified, to reduce the ambiguity and gain more control over the program when being updated.

6.3. Constraints on View

There are scenarios such that an output may include derived values that are calculated from other components of the output, necessitating that the output be consistently updated. For instance, if a rectangle’s width is twice as its height, the width is determined based on the height. The dependency problem on the output is discussed in the putback-based bidirectional transformation language BiGUL [25,26]; since in bidirectional transformation the output is the view, it is called view dependency. A constructor named Dep accepts an additional function to describe the relation of two view elements. During backward transformation, the function is computed to check whether the two elements are consistent with the relation.
Several visual design systems [27,28,29,30] integrate constraint specification. Apparatus [30] is a hybrid graphics editor and programming environment, which is used for creating interactive diagrams. Upon drawing a rectangle, one can utilize arithmetic expressions to define the value of the attributes. For instance, Scale X is defined to be twice the value of Scale Y, as depicted in Figure 18. Consequently, stretching the rectangle either horizontally or vertically results in changes to Scale Y, while the constraint remains intact.

7. Conclusions

This paper presents a bidirectional live programming tool for SVG manipulation, which is capable of controlling the updatability of expressions by marking them with the const keyword. Moreover, by designating the relation expression as unmodifiable using the const keyword, it enables the update of other related elements to re-establish the relation on the output when a related element in the output is altered. From a theoretical perspective, we relaxed the PUTGET property to the WeakPUTGET property, facilitating the reconstruction of relations on the output. We ensure that both the evaluation semantics and the fusion algorithm comply with the well-behavedness properties. To demonstrate the adaptability of our approach, we have effectively implemented 14 benchmark examples that illustrate a variety of updatability scenarios.
Looking ahead, there are two potential areas for improvement. Firstly, although the relation can currently be constructed in the output, it is directly fused into the source program. A more efficient approach would be to store the relation in the output as well. This would allow for the corresponding update of a related element when one element changes, ensuring the consistency of relations in both the program and the output. Secondly, the task of inferring the inherent relations programmed in the source to the output needs to be addressed. Additionally, the delta language could potentially be extended to incorporate recursive drawing [31]. This technique, which employs recursive algorithms to generate complex, often fractal-like, graphics, could significantly enhance the versatility and expressiveness of the delta language in graphical representation.

Author Contributions

Conceptualization, T.Z., X.H. and Z.H.; methodology, T.Z., X.Z., X.H. and Z.H.; software, T.Z. and X.Z.; validation, T.Z., X.Z. and X.H.; investigation, T.Z., X.Z. and X.H.; writing–original draft preparation, T.Z., X.Z. and X.H.; writing–review and editing, T.Z., X.Z., X.H. and Z.H. All authors have read and agreed to the published version of the manuscript.

Funding

This work was supported by the Natural Science Foundation of Fujian Province for Youths (Grant No. 2021J05230) and the Doctor-Initiated Research Fund of Longyan University (Grant No. LB2020010).

Institutional Review Board Statement

Not applicable.

Informed Consent Statement

Not applicable.

Data Availability Statement

Data are contained within the article.

Conflicts of Interest

The authors declare no conflicts of interest.

References

  1. McDirmid, S. Living it up with a live programming language. In Proceedings of the 22nd Annual ACM SIGPLAN Conference on Object-Oriented Programming Systems, Languages and Applications, OOPSLA ’07, Montreal, QC, Canada, 21–25 October 2007; pp. 623–638. [Google Scholar] [CrossRef]
  2. Burckhardt, S.; Fahndrich, M.; de Halleux, P.; McDirmid, S.; Moskal, M.; Tillmann, N.; Kato, J. It’s alive! continuous feedback in UI programming. SIGPLAN Not. 2013, 48, 95–104. [Google Scholar] [CrossRef]
  3. McDirmid, S. The promise of live programming. In Proceedings of the 2nd International Workshop on Live Programming, LIVE, Rome, Italy, 2016; Volume 16. [Google Scholar]
  4. Chugh, R.; Hempel, B.; Spradlin, M.; Albers, J. Programmatic and direct manipulation, together at last. In Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation, Santa Barbara, CA, USA, 13–17 June 2016. [Google Scholar] [CrossRef]
  5. Shneiderman. Direct Manipulation: A Step Beyond Programming Languages. Computer 1983, 16, 57–69. [Google Scholar] [CrossRef]
  6. Hempel, B.; Chugh, R. Semi-Automated SVG Programming via Direct Manipulation. In Proceedings of the 29th Annual Symposium on User Interface Software and Technology, UIST ’16, Tokyo, Japan, 16–19 October 2016; pp. 379–390. [Google Scholar] [CrossRef]
  7. Mayer, M.; Kuncak, V.; Chugh, R. Bidirectional Evaluation with Direct Manipulation. Proc. ACM Program. Lang. 2018, 2, 1–28. [Google Scholar] [CrossRef]
  8. Hempel, B.; Lubin, J.; Chugh, R. Sketch-n-Sketch: Output-Directed Programming for SVG. In Proceedings of the 32nd Annual ACM Symposium on User Interface Software and Technology, UIST ’19, New Orleans, LA, USA, 20–23 October 2019; pp. 281–292. [Google Scholar] [CrossRef]
  9. Zhang, X.; Xie, R.; Guo, G.; He, X.; Zan, T.; Hu, Z. Fusing Direct Manipulations into Functional Programs. Proc. ACM Program. Lang. 2024, 8, 1211–1238. [Google Scholar] [CrossRef]
  10. Czarnecki, K.; Foster, J.N.; Hu, Z.; Lämmel, R.; Schürr, A.; Terwilliger, J.F. Bidirectional Transformations: A Cross-Discipline Perspective. In Theory and Practice of Model Transformations; Paige, R.F., Ed.; Springer: Berlin/Heidelberg, Germany, 2009; pp. 260–283. [Google Scholar]
  11. Foster, J.N.; Greenwald, M.B.; Moore, J.T.; Pierce, B.C.; Schmitt, A. Combinators for Bi-Directional Tree Transformations: A Linguistic Approach to the View Update Problem. In Proceedings of the 32nd ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL ’05, Long Beach, CA, USA, 12–14 January 2005; pp. 233–246. [Google Scholar]
  12. Fischer, S.; Hu, Z.; Pacheco, H. The essence of bidirectional programming. Sci. China Inf. Sci. 2015, 58, 1–21. [Google Scholar] [CrossRef]
  13. Hofmann, M.; Pierce, B.; Wagner, D. Symmetric Lenses. In Proceedings of the 38th Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL ’11, Austin, TX, USA, 26–28 January 2011; pp. 371–384. [Google Scholar]
  14. Ko, H.S.; Hu, Z. An Axiomatic Basis for Bidirectional Programming. Proc. ACM Program. Lang. 2017, 2, 1–29. [Google Scholar] [CrossRef]
  15. Barbosa, D.M.; Cretin, J.; Foster, N.; Greenberg, M.; Pierce, B.C. Matching Lenses: Alignment and View Update. In Proceedings of the 15th ACM SIGPLAN International Conference on Functional Programming, ICFP ’10, Baltimore, MD, USA, 27–29 September 2010; pp. 193–204. [Google Scholar]
  16. Hu, Z.; Mu, S.C.; Takeichi, M. A programmable editor for developing structured documents based on bidirectional transformations. High.-Order Symb. Comput. 2008, 21, 89–118. [Google Scholar] [CrossRef]
  17. Zhu, Z.; Ko, H.S.; Zhang, Y.; Martins, P.; Saraiva, J.; Hu, Z. Unifying Parsing and Reflective Printing for Fully Disambiguated Grammars. New Gener. Comput. 2020, 38, 423–476. [Google Scholar] [CrossRef]
  18. Hidaka, S.; Hu, Z.; Inaba, K.; Kato, H.; Matsuda, K.; Nakano, K. Bidirectionalizing Graph Transformations. In Proceedings of the 15th ACM SIGPLAN International Conference on Functional Programming, ICFP ’10, Baltimore, MD, USA, 27–29 September 2010; pp. 205–216. [Google Scholar]
  19. Hidaka, S.; Asada, K.; Hu, Z.; Kato, H.; Nakano, K. Structural Recursion for Querying Ordered Graphs. In Proceedings of the 18th ACM SIGPLAN International Conference on Functional Programming, ICFP ’13, Boston, MA, USA, 25–27 September 2013; pp. 305–318. [Google Scholar]
  20. Tran, V.D.; Kato, H.; Hu, Z. Programmable View Update Strategies on Relations. Proc. VLDB Endow. 2020, 13, 726–739. [Google Scholar] [CrossRef]
  21. Matsuda, K.; Wang, M. FliPpr: A System for Deriving Parsers from Pretty-Printers. New Gener. Comput. 2018, 36, 173–202. [Google Scholar] [CrossRef]
  22. Cheney, J.; Gibbons, J.; McKinna, J.; Stevens, P. On principles of Least Change and Least Surprise for bidirectional transformations. J. Object Technol. 2017, 16, 3:1–3:31. [Google Scholar] [CrossRef]
  23. Zhang, X.; Hu, Z. Towards Bidirectional Live Programming for Incomplete Programs. In Proceedings of the 44th International Conference on Software Engineering, ICSE ’22, Pittsburgh, PA, USA, 22–27 May 2022; pp. 2154–2164. [Google Scholar] [CrossRef]
  24. Zhang, X.; Guo, G.; He, X.; Hu, Z. Bidirectional Object-Oriented Programming: Towards Programmatic and Direct Manipulation of Objects. Proc. ACM Program. Lang. 2023, 7, 230–255. [Google Scholar] [CrossRef]
  25. Ko, H.S.; Zan, T.; Hu, Z. BiGUL: A formally verified core language for putback-based bidirectional programming. In Proceedings of the 2016 ACM SIGPLAN Workshop on Partial Evaluation and Program Manipulation, PEPM ’16, St. Petersburg, FL, USA, 18–19 January 2016; pp. 61–72. [Google Scholar] [CrossRef]
  26. Hu, Z.; Ko, H.S. Principles and practice of bidirectional programming in BiGUL. In Bidirectional Transformations: International Summer School, Oxford, UK, July 25–29, 2016, Tutorial Lectures; Springer: Cham, Switzerland, 2018; pp. 100–150. [Google Scholar]
  27. Jackiw, R.N.; Finzer, W.F. The geometer’s sketchpad: Programming by geometry. In Watch What I Do: Programming by Demonstration; MIT Press: Cambridge, MA, USA, 1993; pp. 293–307. [Google Scholar]
  28. Xia, H.; Araujo, B.; Grossman, T.; Wigdor, D. Object-Oriented Drawing. In Proceedings of the 2016 CHI Conference on Human Factors in Computing Systems, CHI ’16, San Jose, CA, USA, 7–12 May 2016; pp. 4610–4621. [Google Scholar] [CrossRef]
  29. Jacobs, J.; Gogia, S.; Mundefinedch, R.; Brandt, J.R. Supporting Expressive Procedural Art Creation through Direct Manipulation. In Proceedings of the 2017 CHI Conference on Human Factors in Computing Systems, CHI ’17, Denver, CO, USA, 6–11 May 2017; pp. 6330–6341. [Google Scholar] [CrossRef]
  30. Schachman, T. Apparatus. Available online: http://aprt.us (accessed on 17 February 2025).
  31. Bricault, S. Recursive Drawing. Available online: http://bricault.mit.edu/recursive-drawing (accessed on 17 February 2025).
Figure 1. An output-directed manipulation example in Sketch-n-Sketch.
Figure 1. An output-directed manipulation example in Sketch-n-Sketch.
Information 16 00169 g001
Figure 2. A manipulation-directed example in FuseDM.
Figure 2. A manipulation-directed example in FuseDM.
Information 16 00169 g002
Figure 3. A manipulation-directed example in FuseSVG.
Figure 3. A manipulation-directed example in FuseSVG.
Information 16 00169 g003
Figure 4. Syntax of language DF.
Figure 4. Syntax of language DF.
Information 16 00169 g004
Figure 5. Evaluation rules for DF.
Figure 5. Evaluation rules for DF.
Information 16 00169 g005
Figure 6. Inference rules for expression updatability.
Figure 6. Inference rules for expression updatability.
Information 16 00169 g006
Figure 7. Syntax of direct manipulation language DM.
Figure 7. Syntax of direct manipulation language DM.
Information 16 00169 g007
Figure 8. Semantics of delta language DM (selected rules).
Figure 8. Semantics of delta language DM (selected rules).
Information 16 00169 g008
Figure 9. Semantics of selectors for values ( v v select = v ).
Figure 9. Semantics of selectors for values ( v v select = v ).
Information 16 00169 g009
Figure 10. Fusion example.
Figure 10. Fusion example.
Information 16 00169 g010
Figure 11. Fusing + Δ 2 to the const marked program.
Figure 11. Fusing + Δ 2 to the const marked program.
Information 16 00169 g011
Figure 12. Propagation rules.
Figure 12. Propagation rules.
Information 16 00169 g012
Figure 13. Propagation rules (cont.).
Figure 13. Propagation rules (cont.).
Information 16 00169 g013
Figure 14. Benchmarks.
Figure 14. Benchmarks.
Information 16 00169 g014
Figure 15. A comparison between FuseDM and FuseSVG.
Figure 15. A comparison between FuseDM and FuseSVG.
Information 16 00169 g015
Figure 16. A step-by-step guide to constructing a battery.
Figure 16. A step-by-step guide to constructing a battery.
Information 16 00169 g016
Figure 17. A step-by-step guide to constructing a balanced scale.
Figure 17. A step-by-step guide to constructing a balanced scale.
Information 16 00169 g017
Figure 18. A glimpse of Apparatus.
Figure 18. A glimpse of Apparatus.
Information 16 00169 g018
Table 1. Detailed explanation of P-App3 with an example.
Table 1. Detailed explanation of P-App3 with an example.
DetailExample
1Evaluate e 2 to value. { a 0 id } a 0
2Evaluate e 1 to closure. { a 0 id } ( λ x . ( 1 , x , a ) ) ( { a 0 id } , λ x . ( 1 , x , a ) )
3Fuse the delta dv into the function body e f and obtain  e f . ( + Δ 2 , + Δ 3 ) Δ ( { a 0 id , x 0 id } , { a false , x false } ) ( x , a )
( { a 0 + Δ 3 id , x 0 + Δ 2 id } , { a false , x false } ) ( x , a )
4Construct the function closure ( E f , E b f , λ x . e ) . ( { a 0 + Δ 3 id } , { a false } , λ x . ( x , a ) )
5Fuse the modified function closure into e 1 . ( ( { a 0 + Δ 3 id } , { a false } ) , λ x . ( x , a ) ) ( { a 0 id } , { a false } )
λ x . ( x , a ) ( { a 0 + Δ 3 id } , { a false } ) λ x . ( x , a )
6Fuse the delta dv 2 into e 2 . + Δ 2 ( { a 0 id } , { a false } ) a ( { a 0 + Δ 2 id } , { a false } ) a
7Merge environments and solve conflicts. { a 0 + Δ 3 id } λ x . ( x , a ) a { a 0 + Δ 2 id }
= ( { a 0 id } , λ x . ( x , a + 3 ) ( a + 2 ) )
Table 2. Analysis of benchmarks.
Table 2. Analysis of benchmarks.
IDExampleMultiple Update ChoiceImmutability for Single ValueNumber of Relations
1Precision Floor Plan3
2Mondrian Arch6
3Balance Scale15
4Box Volume21
5Battery2
6Ladder10
7Logo6
8N Boxes6
9Ferris Wheel54
10Tree Branch18
11Target6
12Pencil Tip11
13Arrows28
14Rails38
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.

Share and Cite

MDPI and ACS Style

Zan, T.; Zhang, X.; He, X.; Hu, Z. Intentionally Fusing Direct Manipulations into SVG Programs. Information 2025, 16, 169. https://doi.org/10.3390/info16030169

AMA Style

Zan T, Zhang X, He X, Hu Z. Intentionally Fusing Direct Manipulations into SVG Programs. Information. 2025; 16(3):169. https://doi.org/10.3390/info16030169

Chicago/Turabian Style

Zan, Tao, Xing Zhang, Xiao He, and Zhenjiang Hu. 2025. "Intentionally Fusing Direct Manipulations into SVG Programs" Information 16, no. 3: 169. https://doi.org/10.3390/info16030169

APA Style

Zan, T., Zhang, X., He, X., & Hu, Z. (2025). Intentionally Fusing Direct Manipulations into SVG Programs. Information, 16(3), 169. https://doi.org/10.3390/info16030169

Note that from the first issue of 2016, this journal uses article numbers instead of page numbers. See further details here.

Article Metrics

Back to TopTop