Closed jsmith628 closed 5 years ago
string addition does actually constitute a proper mathematical Monoid
It's not commutative though, which is a basic property of addition.
Of course... strings aren't really numbers, so feel free to reject the changes if you guys want to,
That's my inclination.
but it would definitely make the
Zero
trait decently more viable as a general additive identity for more abstract mathematical crates.
Do you have any real use case for strings in such a crate? This seems like a hypothetical "because we can" kind of feature, rather than something anyone would really need.
While yes, the addition is not commutative, the standard library does already have impl
s on Cow
for both Add
and AddAssign
in stable, and my implementation does fit both the num-traits
docs and standard mathematical definition of zero. So honestly, adding this would probably be worth it if only for the sake of consistency with std
.
Moreover, I'd say that it's just a generally good idea to implement a trait on as many things fit its properties as possible, as this can only increase the possible things you can do with it. In fact, believe it or not, I actually have run into cases where not implementing Zero
on Cow
has restricted something in a crate of mine and cases where I've had to specifically design around the fact that Cow
implements a non-commutative addition.
So honestly, adding this would probably be worth it if only for the sake of consistency with
std
.
IMO this is a wart in std
, but core::ops::Add
is at least defined to support the language operator +
, not necessarily mathematical. The num
crates are meant to be numeric.
Moreover, I'd say that it's just a generally good idea to implement a trait on as many things fit its properties as possible, as this can only increase the possible things you can do with it.
That's debatable, but there's at least an implicit property of being numeric here, which of course strings don't satisfy.
In fact, believe it or not, I actually have run into cases where not implementing
Zero
onCow
has restricted something in a crate of mine
Is that code public? I still find it hard to imagine wanting Zero for Cow
, unless you're just trying to be super generic with anything that implements Add
. Maybe Default
would be a better non-numeric trait for your case?
IMO this is a wart in
std
, butcore::ops::Add
is at least defined to support the language operator+
, not necessarily mathematical. Thenum
crates are meant to be numeric.
I would more-or-less concur that it is a wart in std
, but IMHO I wouldn't actually say that the implementation isn't mathematical. It very much fits within algebra as a monoid. In fact, it actually specifically represents a free-monoid over characters.
That's debatable, but there's at least an implicit property of being numeric here, which of course strings don't satisfy.
As for whether it's numeric, I'd honestly say that the term is incredibly ambiguous. What exactly counts? Does it include only real-number subsets? If so, then we shouldn't have num-complex
. If it's only complex-numbers, then what about Polynomials? They definitely contain a useful 0
. Or what about modular arithmetic? Or vectors? Or matrices?
So, frankly, I feel as though the only way to decide this is with precise mathematical definitions (which string addition does satisfy).
Is that code public? I still find it hard to imagine wanting
Zero for Cow
, unless you're just trying to be super generic with anything that implementsAdd
. MaybeDefault
would be a better non-numeric trait for your case?
There is definitely an element of my wanting to be super generic, but I do have a couple of precise examples:
maths-traits
crate, I had considered designing the API with the assumption that Add
was both commutative and associative, but I decided against that specifically because Cow
addition was non-commutative.maths-traits
.free-algebra
crate and used Cow
instead.I would more-or-less concur that it is a wart in
std
, but IMHO I wouldn't actually say that the implementation isn't mathematical.
I think it's also telling that we're only talking about Cow<'_, str>
here, and not String
because it doesn't implement Add<Self>
.
As for whether it's numeric, I'd honestly say that the term is incredibly ambiguous. What exactly counts? Does it include only real-number subsets? If so, then we shouldn't have
num-complex
. If it's only complex-numbers, then what about Polynomials? They definitely contain a useful0
. Or what about modular arithmetic? Or vectors? Or matrices?
Every one of your further examples has a numeric zero in a way that does not apply to strings, and they can also implement a useful One
. It's a bad sign for strings that Zero
is the only trait here that they could maybe possibly kinda-sorta implement. I think it's just not a good fit.
- Since string addition is effectively just a free-monoid, there is a very real possibility that I would have simply not included them in my
free-algebra
crate and usedCow
instead.
It seems to me that having custom types is actually a good thing, rather than trying to force the std
string types into a more abstract role.
I think it's also telling that we're only talking about
Cow<'_, str>
here, and notString
because it doesn't implementAdd<Self>
.
Yes, exactly. My assumption was that Zero
was for types that implement Add<Self>
and have an additive identity. Does it bother me that Cow<'_, str>
implements Add<Self>
and String
doesn't? Yes. Do I think that this should mean that Zero
is inconsistent in its implementation? No.
Every one of your further examples has a numeric zero in a way that does not apply to strings, and they can also implement a useful
One
. It's a bad sign for strings thatZero
is the only trait here that they could maybe possibly kinda-sorta implement. I think it's just not a good fit.
If matrices and vectors are considered "numeric", then the term literally means nothing. If vectors don't have multiplication or division or a multiplicative identity either, then why should strings have to? Heck, if you need a numeric type, then why not just use num
? That's what it's there for.
Moreover, if a struct shouldn't implement Zero
unless it implements One
, then why aren't they combined into a single Identities
trait? If you're going to make two traits separate, then the implementations should be expected to be.
It seems to me that having custom types is actually a good thing, rather than trying to force the
std
string types into a more abstract role.
Take that up with rust-lang
, then. I just think that if a type is going to implement some algebraic traits, it should implement all that fit.
Rather than arguing about what is a number / numeric, I'm going back to your first concession:
Of course... strings aren't really numbers, so feel free to reject the changes if you guys want to,
I think strings are a bad fit for num-traits
, but of course you should feel free to define a more abstract Zero
in your crates if that broader concept makes sense for you.
Implements
Zero
as the empty string,Cow::Borrowed("")
, forCow<'_,str>
Since
Cow<'_,str>
implementsAdd
,AddAssign
, andClone
, and since string addition does actually constitute a proper mathematical Monoid, I felt it made since to implement theZero
trait onCow
to complete that connection.Of course... strings aren't really numbers, so feel free to reject the changes if you guys want to, but it would definitely make the
Zero
trait decently more viable as a general additive identity for more abstract mathematical crates.