-
Notifications
You must be signed in to change notification settings - Fork 430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changed the field name
to label
#923
Changed the field name
to label
#923
Conversation
@cmichi What do you think about updating |
Hey nice, that you created a PR for this!
:-) I actually had intended to create a ticket for this today! I agree that it's a good idea, but let's keep this to a separate issue. I'll create one where we track this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good on first glance ‒ great that you implemented this!
Got some language remarks. I guess the PSP-22 should also be adapted at some point in the future.
README.md
Outdated
@@ -221,6 +221,7 @@ In a module annotated with `#[ink::contract]` these attributes are available: | |||
| `#[ink(constructor)]` | Applicable to method. | Flags a method for the ink! storage struct as constructor making it available to the API for instantiating the contract. | | |||
| `#[ink(payable)]` | Applicable to ink! messages. | Allows receiving value as part of the call of the ink! message. ink! constructors are implicitly payable. | | |||
| `#[ink(selector = "..")]` | Applicable to ink! messages and ink! constructors. | Specifies a concrete dispatch selector for the flagged entity. This allows a contract author to precisely control the selectors of their APIs making it possible to rename their API without breakage. | | |||
| `#[ink(label = "..")]` | Applicable to ink! messages, ink! constructors and ink! implementation blocks. | Specifies a concrete label of method/trait inside of metadata. This allows a contract author to precisely control the labeling of methods inside of ABI making it possible to rename their methods without breakage. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| `#[ink(label = "..")]` | Applicable to ink! messages, ink! constructors and ink! implementation blocks. | Specifies a concrete label of method/trait inside of metadata. This allows a contract author to precisely control the labeling of methods inside of ABI making it possible to rename their methods without breakage. | | |
| `#[ink(label = "..")]` | Applicable to ink! messages, ink! constructors and ink! implementation blocks. | Specifies a concrete label of a method/trait inside the metadata. This allows a contract author to precisely control the labeling of methods inside of ABI making it possible to rename their methods without breakage. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
#[ink(label = "..")]
| Applicable to ink! messages, ink! constructors and ink! implementation blocks.
Why do we have the need to label ink! implementation blocks? What is the effect of it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Marking the implementation block allows you to specify the prefix before the message or constructor.
The user can use it to remove the prefix of trait, or change the prefix of trait, or add a prefix for the impl section without the trait.
In this PR I described the case when we are using "change the prefix of trait" behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure I like this feature for trait implementation blocks since I see a potential for a lot of confusion. What is an actual concrete use case there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual use case is:
We have a trait with the name Erc20External
. During generation of labels for methods ink! adds Erc20External::
prefix. With this prefix it generates Erc20External::transfer
label. The idea is to label the impl section with the Erc20
label to generate the Erc20::transfer
for the method.
We can remove the label
attribute for the impl section if the label
attribute of the method overrides the prefix(in the current implementation it only overrides the label of method and trait prefix affects it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure I like this feature for trait implementation blocks since I see a potential for a lot of confusion. What is an actual concrete use case there?
@Robbepop Can you elaborate on where you see potential for confusion here? If you haven't seen yet, the issue for this PR states some more of the motivation:
For traits, ink! generates a field in the form of
"name": ["BaseErc20", "new"]
. TheBaseErc20
hereby is a trait implemented by the contract. This exposes internal implementation details of the contract without the developer having any influence over it.
@xgreenx please rebase this on the current |
crates/lang/ir/src/ir/attrs.rs
Outdated
@@ -764,6 +788,18 @@ impl TryFrom<syn::NestedMeta> for AttributeFrag { | |||
} | |||
return Err(format_err!(name_value, "expecteded 4-digit hexcode for `selector` argument, e.g. #[ink(selector = 0xC0FEBABE]")) | |||
} | |||
if name_value.path.is_ident("label") { | |||
if let syn::Lit::Str(lit_str) = &name_value.lit { | |||
let name = lit_str.value(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a check to be a valid Rust identifier.
You can check this by using
syn::parse_str::<syn::Ident>()
.unwrap_or_else(|error| {
panic!("encountered invalid non-identifier namespace argument: {}", error)
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually instead of panicking you should return a proper syn::Error
via format_err!
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot tell either what the better design is.
Let us summarize what you propose:
#[ink(label = "foo")]
on an ink! implementation block is a prefix for#[ink(label = "bar")]
on ink! messages in that same block. So both combined you end up with a labelfoo::bar
.- Any
#[ink(label = "bar")]
on an ink! message or constructor in an ink! implementation block will overwrite the label of the ink! message or constructor entirely. Any#[ink(label = "foo")]
on the ink! implementation block will be silently ignored.
I can so pros and cons and confusion with both points.
Furthermore I still cannot judge how important this feature really is. It seems to just alter some UI components.
I like the change to the metadata format with label
instead of name
and a simple string
instead of a sequence of string
s. However, I don't yet see the value behind the #[ink(label = ..)]
property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am very unsure about #[ink(label = "foo")]
on implementation blocks but I think on ink! dispatchables (constructors and messages) it is probably a good idea.
Semantically I'd prefer that if #[ink(label = "foo")]
is put on some ink! constructor or message then only the label suffix is overwritten. Also we would apply the same semantics for trait impl blocks as with the other properties with the incoming PR #665 . It is no longer possible to alter the properties of ink! trait messages but applying those ink! properties like payable
and selector
to them will act as a guard in case the ink! trait definitions changes. So we could do the same for label
. In fact the ink! trait definition then decides the label
s for all implemented ink! messages. Is that a deal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of the #665 to not alter the properties in impl block, so I agree with the same rules for the label
attribute=)
We need the ability to change the suffix of the method and the prefix of the method in the generated ABI.
Above you described how can be implemented the attribute to change the suffix, I agree with it. Now we need to decide how we can change the prefix in case of traits=)
We can try to move in this direction, but what do you think about next:
The label
and selector
attributes should have the same behavior.
- If someone specified the
label
, it will use this label directly - Otherwise, it generates a label based on the path of the trait, namespace, and the name of the method(It means that the
namespace
attribute also will affect the label in the same way how it affects the selector).
Also, I think, that we need to introduce some mechanism to affect the name of the trait during the generation of the selectors and labels. It will allow the user to specify any part of the selector/label during the generation process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any
#[ink(label = "bar")]
on an ink! message or constructor in an ink! implementation block will overwrite the label of the ink! message or constructor entirely. Any#[ink(label = "foo")]
on the ink! implementation block will be silently ignored.
This is the approach I prefer. My understanding is that the entire reason for this feature is to make it possible for a developer to control what label appears in a UI. If we still concatenate internal implementation details (like the name of the impl
block) to the label it's pointless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, it is why I think that the behavior of labels and selectors must be the same(it is described above :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've lost a bit track of where we are with this PR and where the discussion went. @xgreenx Could you maybe quickly summarize what decision needs to be made for you to be able to finish the PR? |
We need to decide do we need the |
I am strictly against adding the label attribute. the metadata changes are ok. i see no reason in adding a feature where there is no strict requirement and where we are not 100% sure about its design. |
Sure, will adapt it for the master branch and will remove |
…For trait it is string in format "TRAIT_IDENT::METHOD_IDENT"
436a62f
to
6356f80
Compare
label
attribute and update of ABI generation processname
to label
I've updated the PR. In ABI we still use "name" for storage layout and for types. Do I need to update it for storage layout? (because in the case of types we need to update |
@@ -275,11 +275,9 @@ impl Metadata<'_> { | |||
as ::ink_lang::reflect::TraitMessageInfo<#local_id>>::SELECTOR | |||
}}; | |||
let ret_ty = Self::generate_return_type(message.output()); | |||
let label = [trait_ident.to_string(), message_ident.to_string()].join("::"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you prefer this logic here or in from_trait_and_label
on "spec" level?
What do you think about the idea that the namespace will affect the label too(not only selector)? If you agree then I will implement it like this https://github.com/paritytech/ink/blob/master/crates/lang/ir/src/ir/selector.rs#L108
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good point, I think for consistency reasons it would be good.
What are you referring to with from_trait_and_label
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant, that I removed from_trait_and_label
from spec
and implement the logic of concatenating(joining of trait name and method name by "::") here, on generator
level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, got it. It's fine here.
Do you want to implement the namespace affecting the label as well? Could also be done as a follow-up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can implement that in follow-up PR=) @Robbepop What do you think about the namespace affecting the label?
@xgreenx Could you merge |
Nope, no need to adapt those. |
Codecov Report
@@ Coverage Diff @@
## master #923 +/- ##
===========================================
- Coverage 74.15% 63.57% -10.58%
===========================================
Files 246 246
Lines 9258 9249 -9
===========================================
- Hits 6865 5880 -985
- Misses 2393 3369 +976
Continue to review full report at Codecov.
|
@xgreenx The |
* Changed "name" to "label". "label" field is not array, it is string. For trait it is string in format "TRAIT_IDENT::METHOD_IDENT" * Fixed test * Bump version of metadata * Fix metadata variant
Updated the code generation of ABI. Instead of "name" in messages, constructors, arguments, events we are using "label".
Changed the behavior of "label" for messages and constructors, now it is a string instead of an array.
For trait's messages, we will use the "TRAIT_IDENT::MESSAGE_IDENT" format of representation.
This PR is related to #900.