153k Ether Stolen in Parity Multi-Sig Attack
Just skimming through the Solidity docs, I see a lot of unwise decisions there aside from the weird visibility defaults.<p>All state is mutable by default (this includes struct fields, array elements, and locals). Functions can mutate state by default. Both are overridable by explicit specifiers, much like C++ &quot;const&quot;, but you have to remember to do so. Even then, the current implementation doesn&#x27;t enforce this for functions.<p>Integers are fixed-size and wrap around, so it&#x27;s possible to have overflow and underflow bugs. Granted, with 256 bits of precision by default that&#x27;s harder to do than usual... but still pretty easy if you e.g. do arithmetic on two inputs.<p>Operators have different semantics depending on whether the operands are literals or not. For example, 1&#x2F;2 is 0.5, but x&#x2F;y for x==1 and y==2 is 0. Precision of the operation is also determined in this manner - literals are arbitrary-precision, other values are constrained by their types.<p>Copy is by reference or by value depending on where the operands are stored. This is implicit - the operation looks exactly the same in code, so unless you look at declarations, you don&#x27;t know what it actually does. Because mutability is pervasive, this can can have far-reaching effects.<p>Map data type doesn&#x27;t throw on non-existing keys, it just returns the default value.<p>The language has suffixes for literals to denote various units (e.g. &quot;10 seconds&quot; or &quot;1000 ether&quot;). This is purely syntactic sugar, however, and is not reflected in the type system in any way, so &quot;10 second + 1000 ether&quot; is valid code.<p>Statements allow, but do not require, braces around bodies. This means that dangling &quot;else&quot; is potentially an issue, as is anything else from the same class of bugs (such as the infamous Apple &quot;goto fail&quot; bug).<p>Functions can be called recursively with no special effort, but the stack size is rather limited, and it looks like there are no tail calls. So there&#x27;s the whole class of bugs where recursion depth is defined by contract inputs.<p>Order of evaluation is not defined for expressions. This in a language that has value-returning mutating operators like ++!<p>Scoping rules are inherited from JS, meaning that you can declare variables inside blocks, but their scope is always the enclosing function. This is more of an annoyance than a real problem, because they don&#x27;t have closures, which is where JS makes it very easy to shoot yourself in the foot with this approach to scoping.