-
Notifications
You must be signed in to change notification settings - Fork 8
feat!: Make NamedOp
private. Add MakeExtensionOp::name
and MakeOpDef::opdef_name
#2138
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
Conversation
NamedOp
private. Add MakeExtensionOp::name
and `MakeO…NamedOp
private. Add MakeExtensionOp::name
and MakeOpDef::opdef_name
This PR contains breaking changes to the public Rust API. cargo-semver-checks summary
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## release-rs-v0.16.0 #2138 +/- ##
======================================================
+ Coverage 82.90% 82.93% +0.02%
======================================================
Files 227 227
Lines 42288 42333 +45
Branches 38387 38432 +45
======================================================
+ Hits 35060 35107 +47
+ Misses 5360 5357 -3
- Partials 1868 1869 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
Thanks @doug - generally I like this, but I think we should standardize more the method naming - some places we have qualified_name
, others name
yet these are equivalent (I think).
You haven't mentioned why we are doing this - does this close #1496 ?
Also if the goal is to hide NamedOp, but then publically use &T: Into<&'static str>
then I think that would be a retrograde step, but I don't think the latter really is intended for public use, so I think it would be better to clean that up instead...
so I'm 90% of the way to hitting approve but I think I'd like to see what you can do about those!
hugr-core/src/extension/prelude.rs
Outdated
impl MakeOpDef for TupleOpDef { | ||
fn opdef_name(&self) -> OpName { | ||
<&Self as Into<&'static str>>::into(self).into() |
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.
<&Self as Into<&'static str>>::into(self).into() | |
<&'static str>::from(self).into() |
hugr-core/src/extension/simple_op.rs
Outdated
/// Traits implemented by types which can add themselves to [`Extension`]s as | ||
/// [`OpDef`]s or load themselves from an [`OpDef`]. | ||
/// | ||
/// Particularly useful with C-style enums that implement [strum::IntoEnumIterator], | ||
/// as then all definitions can be added to an extension at once. | ||
pub trait MakeOpDef: NamedOp { | ||
pub trait MakeOpDef { | ||
/// TODO docs |
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.
In particular, is this qualified or unqualified?
hugr-core/src/extension/simple_op.rs
Outdated
@@ -70,7 +59,7 @@ pub trait MakeOpDef: NamedOp { | |||
|
|||
/// Description of the operation. By default, the same as `self.name()`. |
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.
/// Description of the operation. By default, the same as `self.name()`. | |
/// Description of the operation. By default, the same as [Self::opdef_name]. |
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.
Or default to empty string...
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 prefer to leave this as is
hugr-core/src/extension/simple_op.rs
Outdated
@@ -150,7 +139,10 @@ pub trait HasDef: MakeExtensionOp { | |||
|
|||
/// Traits implemented by types which can be loaded from [`ExtensionOp`]s, | |||
/// i.e. concrete instances of [`OpDef`]s, with defined type arguments. | |||
pub trait MakeExtensionOp: NamedOp { | |||
pub trait MakeExtensionOp { | |||
/// The name of the operation |
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.
full or unqualified?
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.
Even better, rename the method to qualified_name
or unqualified_name
hugr-core/src/extension/simple_op.rs
Outdated
@@ -188,6 +180,10 @@ pub trait MakeExtensionOp: NamedOp { | |||
|
|||
/// Blanket implementation for non-polymorphic operations - [OpDef]s with no type parameters. | |||
impl<T: MakeOpDef> MakeExtensionOp for T { | |||
fn name(&self) -> OpName { | |||
<Self as MakeOpDef>::opdef_name(self) |
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.
Either MakeOpDef::opdef_name(self)
or doesn't just self.opdef_name()
work?
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.
Yes, this was necessary when opdef_name was called name
hugr-core/src/ops/custom.rs
Outdated
|
||
/// Returns the unqualified name of the operation. e.g. 'arithmetic.iadd' | ||
pub fn qualified_name(&self) -> OpName { | ||
self.name() |
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.
Is this NamedOp::name? So we could rename that to NamedOp::qualified_name, and then you'd have to do NamedOp::qualified_name(self)
, but at least that would be explicit
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.
Alternatively, doc that OpName
s are always qualified (right?), and then call this method name
(i.e. make all .name()
s qualified, and sometimes there is .unqualified_name()
too - in that case, you might want to rename to name_unqualified
because it'll be more obvious browsing the list of autocompletes!)
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.
OpName is not always the name of an extension op, which is the only context were qualified/unqualified makes sense.
I do agree it would be better to move ExtensionOp's NamedOp::name
implementation here, and call qualified_name
from there instead.
@@ -45,6 +45,10 @@ pub enum ConvertOpDef { | |||
} | |||
|
|||
impl MakeOpDef for ConvertOpDef { | |||
fn opdef_name(&self) -> OpName { | |||
<&Self as Into<&'static str>>::into(self).into() |
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.
ditto
impl NamedOp for ArrayScanDef { | ||
fn name(&self) -> OpName { | ||
ARRAY_SCAN_OP_ID | ||
impl From<&ArrayScanDef> for &'static str { |
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 see, so is that how the <&Self as Into<&'static str>>:into(self)
works. This is a bit of an odd declaration - do we parametrize anything <T>...where &T: Into<&'static str>
? I am wondering if maybe we should just put this directly into the impl of MakeOpDef::opdef_name
and do away with this rather odd conversion; what purpose does it serve?
(There are also things like ToString
which are more standard - I haven't seen why we need a trait separate from MakeOpDef, but if we do, then how about using that?)
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.
Ok, this seems to be the only place where we have to do this, so we must be getting this odd conversion some other way for the other places??
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 didn't fix this up, will remove.
Where we use it, the <&'static str>::From<X>
is convenient because it is derived by a strum macro IntoStaticStr
@@ -218,6 +218,11 @@ impl StaticArrayOpDef { | |||
} | |||
|
|||
impl MakeOpDef for StaticArrayOpDef { | |||
fn opdef_name(&self) -> OpName { | |||
let s: &str = self.into(); |
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.
Make standardize this with the others (suggest <&'static str>::from(self).into()
), but see prev. comment, why do we have that made impl From<...> for &'static str
anyway?
@@ -234,8 +236,8 @@ pub(crate) mod test { | |||
|
|||
use super::*; | |||
use crate::std_extensions::arithmetic::float_types::float64_type; | |||
fn get_opdef(op: impl NamedOp) -> Option<&'static Arc<OpDef>> { | |||
EXTENSION.get_op(&op.name()) | |||
fn get_opdef(op: impl Into<&'static str>) -> Option<&'static Arc<OpDef>> { |
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.
Ah, I think this is the (only) place where we're parametrizing over types that have this odd conversion. (So you can pass an actual &'static str
here, or a reference to an op-thing that has that conversion). However, this is only a test method - consider using ToString
here?
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.
Yes I thought this was fine in a test method, but not fine in the API. will reconsider this one.
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.
Thanks Alan. Yes I agree all the name
s are confusing and somewhat incoherent.
To summarise(will move to commit message when we're done):
- Now only
OpType
variants have aNamedOp
impl. OpTypes have aname
, it's that impl. - ExtensionOps/OpaqueOps have a qualified_name and an unqualified_name
- MakeOpDefs have a
opdef_name
(it's unqualified) - MakeExtensionOps have a
name
. (it's unqualified)
What do you think about opdef_id
and op_id
instead?
@@ -355,7 +355,7 @@ pub type OpNameRef = str; | |||
#[enum_dispatch] | |||
/// Trait for setting name of OpType variants. | |||
// Separate to OpTrait to allow simple definition via impl_op_name | |||
pub trait NamedOp { | |||
pub(crate) trait NamedOp { | |||
/// The name of the operation. | |||
fn name(&self) -> OpName; |
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 neither. This trait is implemented by CFG
, DFG
, etc, as well as ExtensionOp
(whose implementation is it's qualfied name).
hugr-core/src/ops/custom.rs
Outdated
|
||
/// Returns the unqualified name of the operation. e.g. 'arithmetic.iadd' | ||
pub fn qualified_name(&self) -> OpName { | ||
self.name() |
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.
OpName is not always the name of an extension op, which is the only context were qualified/unqualified makes sense.
I do agree it would be better to move ExtensionOp's NamedOp::name
implementation here, and call qualified_name
from there instead.
impl NamedOp for ArrayScanDef { | ||
fn name(&self) -> OpName { | ||
ARRAY_SCAN_OP_ID | ||
impl From<&ArrayScanDef> for &'static str { |
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 didn't fix this up, will remove.
Where we use it, the <&'static str>::From<X>
is convenient because it is derived by a strum macro IntoStaticStr
@@ -234,8 +236,8 @@ pub(crate) mod test { | |||
|
|||
use super::*; | |||
use crate::std_extensions::arithmetic::float_types::float64_type; | |||
fn get_opdef(op: impl NamedOp) -> Option<&'static Arc<OpDef>> { | |||
EXTENSION.get_op(&op.name()) | |||
fn get_opdef(op: impl Into<&'static str>) -> Option<&'static Arc<OpDef>> { |
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.
Yes I thought this was fine in a test method, but not fine in the API. will reconsider this one.
Hah, so everything I thought I'd inferred was wrong ;). If we doc that Of course the real way to fix this is to make Name a type with a qualifier/prefix and a final id; everything has only one method returning Name; and you extract just the unqualified bit if you want. (For core CFG/etc. the qualifier is empty, and Name::display omits the intervening
Not sure what you intend here - however, if you mean that an "id" is always qualified (or always unqualified), or indeed is that midpoint (so one has qualified names, unqualified names, and ids, only) then yes that could work. |
If the into-static-string thing works with that |
…pDef::opdef_name` (#2138) BREAKING CHANGE: `NamedOp` is no longer public. Use `OpType`'s `Display` impl for a short string describing the OpType. BREAKING CHANGE: New required trait method `opdef_name` on `MakeOpDef` BREAKING CHANGE: New required trait method `name` on `MakeExtensionOp`
BREAKING CHANGE:
NamedOp
is no longer public. UseOpType
'sDisplay
impl for a short string describing the OpType.BREAKING CHANGE: New required trait method
opdef_name
onMakeOpDef
BREAKING CHANGE: New required trait method
name
onMakeExtensionOp