Repository: vyperlang/vyper

Issue:
VIP: Remove required keyword arguments from builtin functions
## Simple Summary
Vyper should not use required keyword arguments in built-in functions.

1. `raw_call` requires `outsize` and `gas` as keyword args.
2. `slice` requires `start` and `len` as keyword args.

## Motivation
Given the similarity to between Vyper syntax and Python syntax, the current style is unintuitive to write and misleading to read. I believe keyword arguments should **only** be used for optional fields. All required arguments should **always** be positional.

## Specification
1. For `raw_call`, convert `outsize` and `gas` to positional arguments.
   a. Alternatively, `gas` could become an optional argument that defaults to `gasLeft`.
2. For `slice`, convert `start` and `len` to positional arguments.

```python
# current
raw_call(_addr, b"moose", outsize=7, gas=50000)
slice(inp1, start=3, len=3)


# proposed
raw_call(_addr, b"moose", 7, 50000)
slice(inp1, 3, 3)
```

## Backwards Compatibility
This is a breaking change, but it will only require slight modifications to existing contracts.

## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/)



Discussion:
I might have missed some builtins, will update this VIP if I encounter any others.
> Alternatively, `gas` could become an optional argument that defaults to `gasLeft`

This would be what I prefer
> Alternatively, gas could become an optional argument that defaults to gasLeft

I like this but it should be a different VIP
> slice requires start and len as keyword args.

nice to have: just use python slice syntax (but should also be new VIP)
Update this VIP to talk just about `slice`. All conversation from meeting about `raw_call` is moved to #1890

Resolving patch:
diff --git a/vyper/functions/functions.py b/vyper/functions/functions.py
--- a/vyper/functions/functions.py
+++ b/vyper/functions/functions.py
@@ -131,10 +131,10 @@ def _convert(expr, context):
     return convert(expr, context)
 
 
-@signature(('bytes32', 'bytes', 'string'), start='int128', len='int128')
+@signature(('bytes32', 'bytes', 'string'), 'int128', 'int128')
 def _slice(expr, args, kwargs, context):
 
-    sub, start, length = args[0], kwargs['start'], kwargs['len']
+    sub, start, length = args
     if not are_units_compatible(start.typ, BaseType('int128')):
         raise TypeMismatch("Type for slice start index must be a unitless number", expr)
     # Expression representing the length of the slice


Test patch:
diff --git a/tests/parser/features/test_internal_call.py b/tests/parser/features/test_internal_call.py
--- a/tests/parser/features/test_internal_call.py
+++ b/tests/parser/features/test_internal_call.py
@@ -94,11 +94,11 @@ def _catty(x: bytes[5], y: bytes[5]) -> bytes[10]:
 
 @private
 def _slicey1(x: bytes[10], y: int128) -> bytes[10]:
-    return slice(x, start=0, len=y)
+    return slice(x, 0, y)
 
 @private
 def _slicey2(y: int128, x: bytes[10]) -> bytes[10]:
-    return slice(x, start=0, len=y)
+    return slice(x, 0,y)
 
 @public
 def returnten() -> int128:
@@ -160,7 +160,7 @@ def _underscore() -> bytes[1]:
 
 @private
 def _hardtest(x: bytes[100], y: int128, z: int128, a: bytes[100], b: int128, c: int128) -> bytes[201]:  # noqa: E501
-    return concat(slice(x, start=y, len=z), self._underscore(), slice(a, start=b, len=c))
+    return concat(slice(x, y, z), self._underscore(), slice(a, b, c))
 
 @public
 def return_mongoose_revolution_32_excls() -> bytes[201]:
diff --git a/tests/parser/features/test_logging_from_call.py b/tests/parser/features/test_logging_from_call.py
--- a/tests/parser/features/test_logging_from_call.py
+++ b/tests/parser/features/test_logging_from_call.py
@@ -6,7 +6,7 @@ def test_log_dynamic_static_combo(get_logs, get_contract_with_gas_estimation, w3
 @private
 @constant
 def to_bytes(value: uint256) -> bytes[8]:
-    return slice(concat(b"", convert(value, bytes32)), start=24, len=8)
+    return slice(concat(b"", convert(value, bytes32)), 24, 8)
 
 @private
 @constant
@@ -47,7 +47,7 @@ def test_log_dynamic_static_combo2(get_logs, get_contract, w3):
 @private
 @constant
 def to_bytes(value: uint256) -> bytes[8]:
-    return slice(concat(b"", convert(value, bytes32)), start=24, len=8)
+    return slice(concat(b"", convert(value, bytes32)), 24, 8)
 
 @private
 @constant
@@ -115,7 +115,7 @@ def test_original_problem_function(get_logs, get_contract, w3):
 @private
 @constant
 def to_bytes(value: uint256) -> bytes[8]:
-    return slice(concat(b"", convert(value, bytes32)), start=24, len=8)
+    return slice(concat(b"", convert(value, bytes32)), 24, 8)
 
 @private
 @ constant
diff --git a/tests/parser/functions/test_length.py b/tests/parser/functions/test_length.py
--- a/tests/parser/functions/test_length.py
+++ b/tests/parser/functions/test_length.py
@@ -4,8 +4,8 @@ def test_test_length(get_contract_with_gas_estimation):
 
 @public
 def foo(inp: bytes[10]) -> int128:
-    x: bytes[5] = slice(inp, start=1, len=5)
-    self.y = slice(inp, start=2, len=4)
+    x: bytes[5] = slice(inp,1, 5)
+    self.y = slice(inp, 2, 4)
     return len(inp) * 100 + len(x) * 10 + len(self.y)
     """
 
diff --git a/tests/parser/functions/test_slice.py b/tests/parser/functions/test_slice.py
--- a/tests/parser/functions/test_slice.py
+++ b/tests/parser/functions/test_slice.py
@@ -6,14 +6,14 @@ def test_test_slice(get_contract_with_gas_estimation):
 @public
 def foo(inp1: bytes[10]) -> bytes[3]:
     x: int128 = 5
-    s: bytes[3] = slice(inp1, start=3, len=3)
+    s: bytes[3] = slice(inp1, 3, 3)
     y: int128 = 7
     return s
 
 @public
 def bar(inp1: bytes[10]) -> int128:
     x: int128 = 5
-    s: bytes[3] = slice(inp1, start=3, len=3)
+    s: bytes[3] = slice(inp1, 3, 3)
     y: int128 = 7
     return x * y
     """
@@ -33,7 +33,7 @@ def test_test_slice2(get_contract_with_gas_estimation):
 def slice_tower_test(inp1: bytes[50]) -> bytes[50]:
     inp: bytes[50] = inp1
     for i in range(1, 11):
-        inp = slice(inp, start=1, len=30 - i * 2)
+        inp = slice(inp, 1, 30 - i * 2)
     return inp
     """
     c = get_contract_with_gas_estimation(test_slice2)
@@ -51,14 +51,14 @@ def test_test_slice3(get_contract_with_gas_estimation):
 @public
 def foo(inp1: bytes[50]) -> bytes[50]:
     self.x = 5
-    self.s = slice(inp1, start=3, len=3)
+    self.s = slice(inp1, 3, 3)
     self.y = 7
     return self.s
 
 @public
 def bar(inp1: bytes[50]) -> int128:
     self.x = 5
-    self.s = slice(inp1, start=3, len=3)
+    self.s = slice(inp1,3, 3)
     self.y = 7
     return self.x * self.y
     """
@@ -76,7 +76,7 @@ def test_test_slice4(get_contract_with_gas_estimation, assert_tx_failed):
     test_slice4 = """
 @public
 def foo(inp: bytes[10], start: int128, _len: int128) -> bytes[10]:
-    return slice(inp, start=start, len=_len)
+    return slice(inp, start, _len)
     """
 
     c = get_contract_with_gas_estimation(test_slice4)
@@ -100,7 +100,7 @@ def test_slice_at_end(get_contract):
 @public
 def ret10_slice() -> bytes[10]:
     b: bytes[32] = concat(convert(65, bytes32), b'')
-    c: bytes[10] = slice(b, start=31, len=1)
+    c: bytes[10] = slice(b, 31, 1)
     return c
     """
 
diff --git a/tests/parser/syntax/test_block.py b/tests/parser/syntax/test_block.py
--- a/tests/parser/syntax/test_block.py
+++ b/tests/parser/syntax/test_block.py
@@ -40,7 +40,7 @@ def foo() -> decimal(wei / sec):
     """
 @public
 def foo():
-    x: bytes[10] = slice("cow", start=0, len=block.timestamp)
+    x: bytes[10] = slice("cow", 0, block.timestamp)
     """,
     """
 @public
@@ -81,7 +81,7 @@ def add_record():
     """
 @public
 def foo(inp: bytes[10]) -> bytes[3]:
-    return slice(inp, start=block.timestamp, len=3)
+    return slice(inp, block.timestamp, 3)
     """,
     """
 @public
diff --git a/tests/parser/syntax/test_chainid.py b/tests/parser/syntax/test_chainid.py
--- a/tests/parser/syntax/test_chainid.py
+++ b/tests/parser/syntax/test_chainid.py
@@ -46,7 +46,7 @@ def foo() -> decimal(wei / sec):
     """
 @public
 def foo():
-    x: bytes[10] = slice("cow", start=0, len=chain.id)
+    x: bytes[10] = slice("cow", 0, chain.id)
     """,
     """
 @public
@@ -71,7 +71,7 @@ def add_record():
     """
 @public
 def foo(inp: bytes[10]) -> bytes[3]:
-    return slice(inp, start=chain.id, len=3)
+    return slice(inp, chain.id, 3)
     """,
 ]
 
diff --git a/tests/parser/syntax/test_slice.py b/tests/parser/syntax/test_slice.py
--- a/tests/parser/syntax/test_slice.py
+++ b/tests/parser/syntax/test_slice.py
@@ -14,17 +14,17 @@
     """
 @public
 def foo(inp: bytes[10]) -> bytes[2]:
-    return slice(inp, start=2, len=3)
+    return slice(inp, 2, 3)
     """,
     """
 @public
 def foo(inp: int128) -> bytes[3]:
-    return slice(inp, start=2, len=3)
+    return slice(inp, 2, 3)
     """,
     """
 @public
 def foo(inp: bytes[10]) -> bytes[3]:
-    return slice(inp, start=4.0, len=3)
+    return slice(inp, 4.0, 3)
     """
 ]
 
@@ -40,17 +40,17 @@ def test_slice_fail(bad_code):
     """
 @public
 def foo(inp: bytes[10]) -> bytes[3]:
-    return slice(inp, start=2, len=3)
+    return slice(inp, 2, 3)
     """,
     """
 @public
 def foo(inp: bytes[10]) -> bytes[4]:
-    return slice(inp, start=2, len=3)
+    return slice(inp, 2, 3)
     """,
     """
 @public
 def foo() -> bytes[10]:
-    return slice(b"badmintonzzz", start=1, len=10)
+    return slice(b"badmintonzzz", 1, 10)
     """
 ]
 
diff --git a/tests/parser/types/test_bytes.py b/tests/parser/types/test_bytes.py
--- a/tests/parser/types/test_bytes.py
+++ b/tests/parser/types/test_bytes.py
@@ -251,7 +251,7 @@ def to_little_endian_64(value: uint256) -> bytes[8]:
         y = shift(y, 8)
         y = y + bitwise_and(x, 255)
         x = shift(x, -8)
-    return slice(convert(y, bytes32), start=24, len=8)
+    return slice(convert(y, bytes32), 24, 8)
 
 @public
 def set_count(i: uint256):
diff --git a/tests/parser/types/test_bytes_literal.py b/tests/parser/types/test_bytes_literal.py
--- a/tests/parser/types/test_bytes_literal.py
+++ b/tests/parser/types/test_bytes_literal.py
@@ -45,7 +45,7 @@ def test_bytes_literal_splicing_fuzz(get_contract_with_gas_estimation):
 @public
 def foo(s: int128, L: int128) -> bytes[100]:
         x: int128 = 27
-        r: bytes[100] = slice(b"{0}", start=s, len=L)
+        r: bytes[100] = slice(b"{0}", s, L)
         y: int128 = 37
         if x * y == 999:
             return r
@@ -55,7 +55,7 @@ def foo(s: int128, L: int128) -> bytes[100]:
 def bar(s: int128, L: int128) -> bytes[100]:
         self.moo = b"{0}"
         x: int128 = 27
-        r: bytes[100] = slice(self.moo, start=s, len=L)
+        r: bytes[100] = slice(self.moo, s, L)
         y: int128  = 37
         if x * y == 999:
             return r
@@ -64,7 +64,7 @@ def bar(s: int128, L: int128) -> bytes[100]:
 @public
 def baz(s: int128, L: int128) -> bytes[100]:
         x: int128 = 27
-        self.moo = slice(b"{0}", start=s, len=L)
+        self.moo = slice(b"{0}", s, L)
         y: int128 = 37
         if x * y == 999:
             return self.moo
diff --git a/tests/parser/types/test_bytes_zero_padding.py b/tests/parser/types/test_bytes_zero_padding.py
--- a/tests/parser/types/test_bytes_zero_padding.py
+++ b/tests/parser/types/test_bytes_zero_padding.py
@@ -14,7 +14,7 @@ def to_little_endian_64(value: uint256) -> bytes[8]:
         y = shift(y, 8)
         y = y + bitwise_and(x, 255)
         x = shift(x, -8)
-    return slice(convert(y, bytes32), start=24, len=8)
+    return slice(convert(y, bytes32), 24, 8)
 
 @public
 @constant
diff --git a/tests/parser/types/test_string.py b/tests/parser/types/test_string.py
--- a/tests/parser/types/test_string.py
+++ b/tests/parser/types/test_string.py
@@ -61,7 +61,7 @@ def test_string_slice(get_contract_with_gas_estimation, assert_tx_failed):
     test_slice4 = """
 @public
 def foo(inp: string[10], start: int128, _len: int128) -> string[10]:
-    return slice(inp, start=start, len=_len)
+    return slice(inp, start, _len)
     """
 
     c = get_contract_with_gas_estimation(test_slice4)