bank: public({
account_balance: num,
person: bytes32
}[num])
@public
@payable
def transfer(sender_accno: num, reciever_accno: num, amount: num):
if self.bank[sender_accno].account_balance >= amount:
pass
throwing error "AttributeError: 'Name' object has no attribute 'value'
" at this line
if self.bank[sender_accno].account_balance >= amount:
account_balance and amount are both of same type 'num' and it does support >= comparison operator. So, what's wrong with that?
Hi! I was using 'dynamic' in a very fast and loose sense based on the issues I read and vyper's surface similarity to python. But after reading more of the vyper source and testing it out, I found that vyper is much more static than I originally thought.
For instance, based on the following issue ethereum/vyper#582, it looked like [ 1, 2.0, 3 ]
was valid vyper. (allowing mixed type lists would result in a dynamically typed language because you can't determine the list element types at compile time). When i went to test it out though, and reading through this channel's history, it looks like mixed typed lists don't compile.
Another thing I noticed was about the semantics of None
. It seems that None
inhabits every type - but at least you can't have a None
with underspecified type (e.g. foo = None
is an invalid declaration of foo
). Reading through some IR output though it seems None
is just an alias for 0
, which seems typesafe but obfuscating.
My comment about dynamic execution was based on ethereum/vyper#590, as well as vyper's surface similarity to python (which allows code rewriting at runtime). But I see after playing with vyper some more that block-local functions (or really any other mechanism which could result in contract-local looping/recursion) are disallowed. This is good because it improves the ability to statically trace execution! Now correct me if I'm wrong here but does this mean vyper is not Turing complete? Or is there still a back door to recursion through remote calls via raw_call
?
So with the caveat that control flow is a very tricky design area, I think static analysis would be improved further though by requiring all if statements to have both branches and disallowing short-circuiting / remote calls except in very explicit contexts. For instance in Haskell, 'short-circuiting' basically requires a monadic context in order to happen. I think having a limited effects system (which decorators already provide some mileage towards) could help solve a lot of these problems.
For instance, I was thinking about ethereum/vyper#590 and it seems that the issue is stemming from having two separate 'effect systems' for functions-which-don't-return-anything and functions-which-return-something. If they had been reified into a single type, making pass
an alias for return void
(and disallowing signatures like def foo()
, instead requiring def foo() -> void
), then of course def foo() -> num
couldn't end in pass
(aka return void
) because that wouldn't type check.
It's just an idea - in practice it would probably be too draconian to require users to add return void
everywhere, although perhaps functions could be annotated with default return values.