<p>For example, Python has lists, sets and dictionaries as language-level primitives that can be constructed using syntactic sugar <code>[1,2,3], {'a': 1, 'b': 2}</code> while Java has interfaces for each of these structures, no main/canonical/recommended implementation for them, and no special syntax for creating or accessing them. Why would a language avoid raising a data structure to first-class status by giving it such a syntax?</p>

<data-structures><interfaces>
What are the downsides of having no syntactic sugar for data collections?
CC BY-SA 4.0
2023-06-28T14:38:37.607Z
I think "intrinsic" is a better word than "primitive" here. Normally a [primitive type](https://en.wikipedia.org/wiki/Primitive_data_type) means one which represents a single value, as opposed to a [compound type](https://en.wikipedia.org/wiki/Composite_data_type) or aggregate type which represents a grouping or collection of values.
kaya3
CC BY-SA 4.0
2023-06-28T14:48:44.150Z
Intrinsic has a very heavy meaning in compilers and optimization though... builtins might be an even better nomenclature?
kouta-kun
CC BY-SA 4.0
2023-06-28T14:55:25.767Z
[Wikipedia](https://en.wikipedia.org/wiki/Intrinsic_function) seems to think "intrinsic function" and "built-in function" are synonyms, but if there's a technical difference then perhaps built-in is better, sure.
kaya3
<p>The benefits to syntactic sugar for primitives is obvious; it's much easier to construct common collections, and much more readable too.</p>
<p>Disadvantages are less obvious:</p>
<h3>Avoiding being opinionated</h3>
<p>Syntax must by nature pick one specific implementation for lists. This may be undesirable. For example in Java, because of its Object Oriented principles, emphasizes you must pick the interface separately from the implementation, so choosing an <code>ArrayList</code> instead of a <code>LinkedList</code> would violate this principle.</p>
<h3>Running out of brackets</h3>
<p>Most languages that have syntactic sugar use <code>[] {} ()</code> maybe <code>&lt;&gt;</code>. You can in some cases re-use the same syntax for multiple types of data structures like Python, which uses <code>{}</code> for both sets and dicts; but even there, there is ambiguity.</p>
<p>This leads fundamentally to a divide between first degree and second degree data structures. This encourages programmers to reach for the basic list or dict when something like a heap or binary search tree would fit better.</p>
<h3>Syntactic Ambiguities</h3>
<p>There is a common ambiguous parsing case in Javascript:</p>
<pre class="lang-js prettyprint-override"><code>()=&gt;{
   a: 2
   b: 3
}
</code></pre>
<p>(note the missing comma is intentional)</p>
<p>You may expect this to return a dict with keys <code>a</code> and <code>b</code> but really this is a function body. To create an object you would need to wrap it in parentheses.</p>
<p>Just not having syntactic sugar for data collections, or restricting it to just <code>[]</code> in the style of C, would avoid this problem.</p>

CC BY-SA 4.0
2023-06-28T06:16:53.393Z
2024-07-28T10:22:43.153Z
2024-07-28T10:22:43.153Z
mousetail 'he-him'
CC BY-SA 4.0
2023-06-28T23:44:39.947Z
"Syntax must by nature pick one specific implementation for list" – That's not necessarily true. There is no reason why a literal cannot be syntactic sugar for a method call. In fact, a lot of newcomers to Ruby seem to be surprised by the fact that `[]`, `""`, `{}`, and friends *do not* call `Array.new`, `String.new`, and `Hash.new`. I always like to look at stuff that surprises newcomers to try and get a sense of what is "natural", so literals translating into method calls seems to be a natural thing … just not to language designers. There was a research project called "scala-virtualized" …
Jörg W Mittag
CC BY-SA 4.0
2023-06-28T23:52:11.157Z
… whose goal it was to improve Scala's suitability for internal DSLs by translating most builtin language features (e.g. `while` loops, conditional expressions, and, relevant to this discussion, object construction) into method calls (i.e. virtual methods, hence the name) the same way it is already done for `for` comprehensions. The [Ioke](https://ioke.org) and [Seph](https://seph-lang.org) languages translate literals into method calls, e.g. `23` is translated into `internal:createNumber("23")` (not quite: the string being passed to the method is not an Ioke string, it is a "strange string",
Jörg W Mittag
CC BY-SA 4.0
2023-06-28T23:53:21.223Z
… i.e. a native string of the underlying runtime platform (JVM, .NET, ECMAScript, etc.)). See https://ioke.org/wiki/index.php/Guide#Integers and https://ioke.org/dok/latest/kinds/DefaultBehavior/Internal.html#C0060 String literals are translated into `internal:createText`, Regexp literals into `internal:createRegexp`, and so on. Collection literals are just normal "around-fix" methods, i.e. `[1, 2, 3]` is just am different way of writing `[](1, 2, 3)`, and so on.
Jörg W Mittag
<blockquote>
<p>Why would a language prefer to mark its' builtin primitives as first-class citizens with specific syntax for them?</p>
</blockquote>
<p>Why have special syntax for common data structures? Because it’s convenient! No more and no less. But this is not fundamentally tethered to whether the <em>data structure implementations</em> are wired into the language. Your original question asked “What are the downsides of data structures being interfaces instead of primitives?” and while your revised question focuses on that somewhat less, I think an exploration is still relevant.</p>
<p>Whether data structures are somehow primitive is essentially orthogonal to both (a) whether they are accessed through interfaces or (b) whether they support literal syntax. After all, what makes something “primitive”, really? There are many different degrees of “primitiveness”:</p>
<ul>
<li><p>At the deepest level, a primitive operation might be so deeply wired into the evaluator that it is actually impossible to (acceptably) implement as a derived concept. For example, we would generally call conditional branching or lambda expressions primitive in this sense.</p>
</li>
<li><p>Slightly less deeply, we might call something primitive if it has special integration with other features of the language. For example, the JavaScript <code>typeof</code> operator distinguishes certain wired-in classes of values, so reimplementations will be distinguishable from the builtin versions.</p>
</li>
<li><p>We might call other things primitive simply because they have special syntax, even though they are really otherwise just ordinary values in the programming language. Literal expressions fall into this category.</p>
</li>
<li><p>Finally, we might call certain things primitives if they’re just such a deeply integral part of the standard library that it is impossible to choose <em>not</em> to include them in your program because certain evaluation rules or aspects of the compiler rely upon them. Many classes in the <code>java.lang</code> package fall into this category, like <code>NullPointerException</code> (though some of them are primitive in a somewhat deeper sense).</p>
</li>
</ul>
<p>None of this really has anything to do with how you choose to expose the functionality itself. Interfaces in the Java sense are really a combination of two features:</p>
<ul>
<li><p>They’re a feature of Java’s static type system that allows for a form of polymorphism.</p>
</li>
<li><p>They’re a feature of Java’s dynamic type system that allows checked runtime casts and reflection.</p>
</li>
</ul>
<p>The former of these simply doesn’t apply to Python because Python is dynamically typed, and the latter doesn’t apply to Python because Python doesn’t have checked runtime casts or interface-based reflection. So the answer to “why doesn’t Python expose lists via a Java-style interface” is “Python doesn’t have Java-style interfaces”.</p>
<p>Now, of course, it is true that Python chooses to specify some of the implementation details of its lists, but there is no fundamental need for it to do so. The concrete implementation of a Python list as a linked list or an array is only observable in its performance characteristics. The implementation of lists <em>could</em> be altered, and Python programs would still work, though they might perform differently. So you really need to pin down what you mean by “interface” in order for the question to mean much.</p>
<p>Finally, there is not any fundamental need for literal syntax to correspond to a builtin or even any single concrete type. In Haskell, numeric literals are overloaded, so the literal <code>42</code> can be given a user-defined type; the meaning of the literal is determined based on its type. Furthermore, the <code>OverloadedStrings</code> and <code>OverloadedLists</code> language extensions generalize this concept to string literals and list literals, respectively. However, this overloading adds some complexity to the language, and Python has always been a language where there should be <a href="https://peps.python.org/pep-0020/" rel="noreferrer">“only one way to do it”</a>. So the fact that Python does not choose this route is not particularly surprising.</p>
<p><strong>tl;dr</strong>: Python chooses to have special syntax for built-in data structures because it’s convenient and because Python programmers have a culture of preferring simple, consistent defaults over more complex flexibility. Java chooses not to provide special syntax because it is exceptionally syntactically conservative (it famously does not permit operator overloading). But you could use or design a language that works differently if you have different preferences or priorities.</p>

CC BY-SA 4.0
2023-06-28T06:03:04.820Z
2023-06-28T06:03:04.820Z
Alexis King
CC BY-SA 4.0
2023-06-28T06:05:19.910Z
Sorry I changed the end of the question while you were writing, but this is a great answer and exactly what I was asking about!
kouta-kun
CC BY-SA 4.0
2023-06-29T02:34:17.973Z
For another possibly interesting example of not wiring data structures into the language while still having syntactic sugar for them, C# collection initializers allow succinct initialisation of any collection, very loosely defined as anything that is `IEnumerable` and has an `Add` method (which is a very low bar to meet, and supports both single and multiple parameters in that method, or even multiple overloads).
Miral
# What are the downsides of having no syntactic sugar for data collections?
Posted by: username_0 on 2023-06-28
For example, Python has lists, sets and dictionaries as language-level primitives that can be constructed using syntactic sugar `[1,2,3], {'a': 1, 'b': 2}` while Java has interfaces for each of these structures, no main/canonical/recommended implementation for them, and no special syntax for creating or accessing them. Why would a language avoid raising a data structure to first-class status by giving it such a syntax?
**Tags:** data-structures interfaces
> **Comments:**
> **username_1**: I think "intrinsic" is a better word than "primitive" here. Normally a [primitive type](https://en.wikipedia.org/wiki/Primitive_data_type) means one which represents a single value, as opposed to a [compound type](https://en.wikipedia.org/wiki/Composite_data_type) or aggregate type which represents a grouping or collection of values.  
> **username_0**: Intrinsic has a very heavy meaning in compilers and optimization though... builtins might be an even better nomenclature?  
> **username_1**: [Wikipedia](https://en.wikipedia.org/wiki/Intrinsic_function) seems to think "intrinsic function" and "built-in function" are synonyms, but if there's a technical difference then perhaps built-in is better, sure.  
---
## 2 answers
### Answer by username_4 on 2023-06-28. Score: 11 | Accepted answer
> Why would a language prefer to mark its' builtin primitives as first-class citizens with specific syntax for them?

Why have special syntax for common data structures? Because it’s convenient! No more and no less. But this is not fundamentally tethered to whether the *data structure implementations* are wired into the language. Your original question asked “What are the downsides of data structures being interfaces instead of primitives?” and while your revised question focuses on that somewhat less, I think an exploration is still relevant.

Whether data structures are somehow primitive is essentially orthogonal to both (a) whether they are accessed through interfaces or (b) whether they support literal syntax. After all, what makes something “primitive”, really? There are many different degrees of “primitiveness”:

* At the deepest level, a primitive operation might be so deeply wired into the evaluator that it is actually impossible to (acceptably) implement as a derived concept. For example, we would generally call conditional branching or lambda expressions primitive in this sense.
* Slightly less deeply, we might call something primitive if it has special integration with other features of the language. For example, the JavaScript `typeof` operator distinguishes certain wired-in classes of values, so reimplementations will be distinguishable from the builtin versions.
* We might call other things primitive simply because they have special syntax, even though they are really otherwise just ordinary values in the programming language. Literal expressions fall into this category.
* Finally, we might call certain things primitives if they’re just such a deeply integral part of the standard library that it is impossible to choose *not* to include them in your program because certain evaluation rules or aspects of the compiler rely upon them. Many classes in the `java.lang` package fall into this category, like `NullPointerException` (though some of them are primitive in a somewhat deeper sense).

None of this really has anything to do with how you choose to expose the functionality itself. Interfaces in the Java sense are really a combination of two features:

* They’re a feature of Java’s static type system that allows for a form of polymorphism.
* They’re a feature of Java’s dynamic type system that allows checked runtime casts and reflection.

The former of these simply doesn’t apply to Python because Python is dynamically typed, and the latter doesn’t apply to Python because Python doesn’t have checked runtime casts or interface-based reflection. So the answer to “why doesn’t Python expose lists via a Java-style interface” is “Python doesn’t have Java-style interfaces”.

Now, of course, it is true that Python chooses to specify some of the implementation details of its lists, but there is no fundamental need for it to do so. The concrete implementation of a Python list as a linked list or an array is only observable in its performance characteristics. The implementation of lists *could* be altered, and Python programs would still work, though they might perform differently. So you really need to pin down what you mean by “interface” in order for the question to mean much.

Finally, there is not any fundamental need for literal syntax to correspond to a builtin or even any single concrete type. In Haskell, numeric literals are overloaded, so the literal `42` can be given a user-defined type; the meaning of the literal is determined based on its type. Furthermore, the `OverloadedStrings` and `OverloadedLists` language extensions generalize this concept to string literals and list literals, respectively. However, this overloading adds some complexity to the language, and Python has always been a language where there should be [“only one way to do it”](https://peps.python.org/pep-0020/). So the fact that Python does not choose this route is not particularly surprising.

**tl;dr**: Python chooses to have special syntax for built-in data structures because it’s convenient and because Python programmers have a culture of preferring simple, consistent defaults over more complex flexibility. Java chooses not to provide special syntax because it is exceptionally syntactically conservative (it famously does not permit operator overloading). But you could use or design a language that works differently if you have different preferences or priorities.
> **Comments:**
> **username_0** (2023-06-28): Sorry I changed the end of the question while you were writing, but this is a great answer and exactly what I was asking about!  
> **username_5** (2023-06-29): For another possibly interesting example of not wiring data structures into the language while still having syntactic sugar for them, C# collection initializers allow succinct initialisation of any collection, very loosely defined as anything that is `IEnumerable` and has an `Add` method (which is a very low bar to meet, and supports both single and multiple parameters in that method, or even multiple overloads).  
---
### Answer by username_2 on 2023-06-28. Score: 3
The benefits to syntactic sugar for primitives is obvious; it's much easier to construct common collections, and much more readable too.
Disadvantages are less obvious:
Avoiding being opinionated
Syntax must by nature pick one specific implementation for lists. This may be undesirable. For example in Java, because of its Object Oriented principles, emphasizes you must pick the interface separately from the implementation, so choosing an ArrayList instead of a LinkedList would violate this principle.
Running out of brackets
Most languages that have syntactic sugar use [] {} () maybe <>. You can in some cases re-use the same syntax for multiple types of data structures like Python, which uses {} for both sets and dicts; but even there, there is ambiguity.
This leads fundamentally to a divide between first degree and second degree data structures. This encourages programmers to reach for the basic list or dict when something like a heap or binary search tree would fit better.
Syntactic Ambiguities
There is a common ambiguous parsing case in Javascript:
()=>{
   a: 2
   b: 3
}

(note the missing comma is intentional)
You may expect this to return a dict with keys a and b but really this is a function body. To create an object you would need to wrap it in parentheses.
Just not having syntactic sugar for data collections, or restricting it to just [] in the style of C, would avoid this problem.
> **Comments:**
> **username_3** (2023-06-28): "Syntax must by nature pick one specific implementation for list" – That's not necessarily true. There is no reason why a literal cannot be syntactic sugar for a method call. In fact, a lot of newcomers to Ruby seem to be surprised by the fact that `[]`, `""`, `{}`, and friends *do not* call `Array.new`, `String.new`, and `Hash.new`. I always like to look at stuff that surprises newcomers to try and get a sense of what is "natural", so literals translating into method calls seems to be a natural thing … just not to language designers. There was a research project called "scala-virtualized" …  
> **username_3** (2023-06-28): … whose goal it was to improve Scala's suitability for internal DSLs by translating most builtin language features (e.g. `while` loops, conditional expressions, and, relevant to this discussion, object construction) into method calls (i.e. virtual methods, hence the name) the same way it is already done for `for` comprehensions. The [Ioke](https://ioke.org) and [Seph](https://seph-lang.org) languages translate literals into method calls, e.g. `23` is translated into `internal:createNumber("23")` (not quite: the string being passed to the method is not an Ioke string, it is a "strange string",  
> **username_3** (2023-06-28): … i.e. a native string of the underlying runtime platform (JVM, .NET, ECMAScript, etc.)). See https://ioke.org/wiki/index.php/Guide#Integers and https://ioke.org/dok/latest/kinds/DefaultBehavior/Internal.html#C0060 String literals are translated into `internal:createText`, Regexp literals into `internal:createRegexp`, and so on. Collection literals are just normal "around-fix" methods, i.e. `[1, 2, 3]` is just am different way of writing `[](1, 2, 3)`, and so on.  
---
