tk3369 / BinaryTraits.jl

Can do or not? It's easy. See https://tk3369.github.io/BinaryTraits.jl/dev/
MIT License
53 stars 3 forks source link

Handling the prefixes. #50

Open Tokazama opened 4 years ago

Tokazama commented 4 years ago

This is a pretty minor issue but prefixes are constants so they print out as Positive or Negative. There's clearly an advantage to having a constant instead needlessly creating a bunch of extra types, like unique binary prefix types. The only idea I really have is to create a specialized show method inside the @trait macro. Something like...

function Base.show(io::IO, ::MIME"text/plain", ::Negative{T}) where {T<:NewlyCreatedTrait}
    print(io, "Not{$T}")
end

I don't see any other way of doing this than defining show inside the macro because that's the only place you'll be able to track down the actually prefix syntax that is used.

It's also not a terribly big deal, unless for some reason people are printing a prefix in the REPL, so unless there's a more ideal solution available this might not even be worth addressing.

tk3369 commented 4 years ago

Yeah, I knew about this problem although I have been ignoring it so far... 😄

If it becomes a much desired feature, then I wouldn't mind creating the prefix types dynamically. The user can just call a function that eval's a new prefix type into the BinaryTraits.Prefix module.

BTW, I chose the words Positive and Negative for the reason that they are generic enough to understand. The other words like Is/Not assumes a noun to be followed. Likewise, Can/Cannot assumes a word and Is/Not assumes a noun. So using those makes it look awkward.

Tokazama commented 4 years ago

Yeah, I think this approach makes the most sense because it avoids creating unnecessary types. It only becomes a problem if the trait's prefixes are intended as part of non-developer API.

For the record, in case this issue actually does go forward some day in the future, here's one idea I had.

@trait MyTrait prefix Is, IsNot

could be equivalent

struct MyTrait end

if !@isdefined(Is)
    const Is{P} = Positive{P}
end

if !@isdefined(Is)
    const IsNot{P} = Negative{P}
end

struct IsMyTrait <: Is{MyTrait} end
struct IsNotMyTrait <: IsNot{MyTrait} end

I think the nice thing about this approach on top of printing stuff it also freely creates new prefixes and makes it easier for people to think about traits in a flexible way. For example, I want a trait that determines if indexing with a particular type is a key or standard integer indexing and I make @trait Indexing prefix Key,Index. It's not something I'd think of as positive or negative, but it's still a binary trait.

All this being said, none of this isn't possible given the current design. It just takes a little extra thought for someone not use to traits.