solidity
solidity copied to clipboard
Introduce a type definition keyword
Solidity has struct
by which arbitrary complex data structures can be created and referenced through named members. I find struct's, as a type, are particularly handy when coupled with a library through the using X for Y
convention. But for some complex types names aren't necessarily needed but they can't be passed to functions and libraries (or I don't know how) without a struct
wrapper....
library LibFoo {
struct MyUneccessaryStruct {
mapping (uint => mapping (uint => string)) IWishIDidnotHaveToDereferenceThisNameEveryTime
}
function libFunc(MyStruct self, uint a, uint b) internal {
return self.IWishIDidnotHaveToDereferenceThisNameEveryTime[a][b];
}
}
contract Foo {
using LibFoo for LibFoo.MyUneccessaryStruct;
LibFoo.MyUneccessaryStruct bar;
function foobar(uint a, uint b, string message) returns (string) {
bar.IWishIDidnotHaveToDereferenceThisNameEveryTime[a][b] = message;
return bar.libFunc(a,b);
}
What I would like to see is a type definition keyword (typedef
) to simplify and enhance the usability of complex types in the following sense...
library LibFoo {
typedef mapping (uint => mapping (uint => string)) MyComplexType;
function libFunc(MyComplexType storage self, uint a, uint b) internal returns (string) {
return self[a][b];
}
}
contract Foo {
using LibFoo for LibFoo.MyComplexType;
LibFoo.MyComplexType bar;
function foobar(uint a, uint b, string message) returns (string) {
bar[a][b] = message;
return bar.libFunc(a,b);
}
}
Duplicate of #1013.
Not really, I'm proposing the naming of custom data types, not references/pointers/macros to instantiated variables which seems the subject of #1013
It is not really a duplicate, but there are examples of what is planned. Something like alias x = complicatedtype
or using x = complicatedtype
or type x = complicatedtype
.
Is there still no type alias support in Solidity?
Type aliases would be useful for simpler use cases (besides complex mapping types):
Let's say I am writing an application that makes use of several different struct
types, each identified by some opaque public key (maybe a hash, or even an integer ID.) This identifier type might be bytes32
in all cases.
As a result, it'd be difficult to look at the code where this ID type is used and discern what kind of record it is. If everything is bytes32
, there's no semantic indication what kind of struct
it refers to. Further, if a library defines methods that performs lookup by ID, users of that library are forced to do something like using Lib for bytes32
, instead of something more semantic.
Additionally, in the course of development, it might become clear that bytes32
is not the correct data type to use for certain IDs, and then the developer would have to find all and only the relevant bytes32
declarations and change those.
By allowing something like type widgetId = bytes32
, it'd avoid all of these problems, and I suspect not break much else in the language.
Not really, I'm proposing the naming of custom data types, not references/pointers/macros to instantiated variables which seems the subject of #1013
Actually if you look at all the comments it started out as a references, but in the comments most of the discussion was about typedef
s 😉
Adding motivation from #7728. This issue can apply to typedeffing structs as well as other primitive types.
Abstract
Add language construct for creating user-defined names for types.
Motivation
Because I see somebody writing code like this:
struct AgreementParams {
uint120 ratio;
uint8 ratioType;
uint128 countdownLength;
}
...
(
uint256 ratio,
uint8 ratioType,
uint256 agreementCountdown
) = abi.decode(agreementParams, (uint256, uint8, uint256));
Specification
Add a new keyword typedef
or alias
to allow new scalar (not enum or struct) types.
Example:
contract ABC {
typedef uint128 TimePeriod;
struct AgreementParams {
uint120 ratio;
uint8 ratioType;
TimePeriod countdownLength;
}
}
...
(
uint256 ratio,
uint8 ratioType,
TimePeriod agreementCountdown
) = abi.decode(agreementParams, (uint256, uint8, TimePeriod));
This declaration will be visible at the contract top-level (storage declarations), functions (parameters and declarations) and inherited contracts.
This new feature will also be available for interfaces. In the generated ABI it will still use the canonical (e.g. uint) types.
Backwards Compatibility
This is additive, no BC issues.
Practical use case for user-defined type aliases: https://hackernoon.com/beware-the-solidity-enums-9v1qa31b2
The article presents a problem where you use enums in a contract and later you want to be able to add new values to that enum without having to recompile the contract. Currently Solidity adds runtime checks that reject values other than ones included in the enum definition which makes this impossible. We have a feature request to remove the check (#9986).
I think that this use case would be better served by being able to define a custom integer type with a set of constants (https://github.com/ethereum/solidity/issues/9986#issuecomment-708521338). Constants are already there so we're just missing the support for custom types.
Any update on this? Having a simple alias to reduce typing would be nice. No fancy side effects, just a "dumb" type alias.
We do have user-defined value types these days, if you want a full type abstraction instead of a mere alias (even though only for value types so far). We may (or may not) still additionally introduce type aliases in the future, if only for providing backwards compatibility aliases for new generic builtin type definitions, but we do not plan on spending resources on this in the near future and before making progress with generics in the language in the first place.
Not sure why I am being "thumbs down"ed
contract SomeContract {
struct ComplexParams {
//...
}
function func(ComplexParams params) internal {
//...
}
}
contract SomeContractFactory {
using ComplexParams = SomeContract.ComplexParams; // introduce shorthand
using SomeContract.ComplexParams; // or bring into scope
function func() internal {
ComplexParams memory params = ComplexParams(/* ... */);
// without the aliases have to type SomeContract.ComplexParams everywhere
}
}
We use user-defined value types for "Strong typing", and it's very useful, thank you. However, for a simple alias, it's overkill to wrap and unwrap. The usecase is entirely different to user-defined value types. Aliases help ergonomics, and keeping things scoped appropriately. Without aliases people may get tempted to pull out inner struct definitions and end up with something like this to save on typing:
struct ComplexParams {
//...
}
contract SomeContract {
function func(ComplexParams params) internal {
//...
}
}
contract SomeContractFactory {
function func() internal {
ComplexParams memory params = ComplexParams(/* ... */);
}
}
This issue has been marked as stale due to inactivity for the last 90 days. It will be automatically closed in 7 days.
Unmarking this from being stale - this is roadmap relevent, since we'll need type aliases eventually if only for restoring backwards compatible aliases for generic "user"-defined versions of the currently builtin types (i.e. type_synonym uint256 = uint<256>;
to get the idea, even though the ultimate syntax will differ).
Plus one for allowing something like using SomeLibrary.StructDefinedTherein;
to reduce verbosity when referencing that struct type!