Hi Kevin, As you're gleaming, you will need to implement a set of basic functions, and that set isn't tiny. That said, once you implement this minimal set, your type should be usable everywhere else that a Real is accepted (even when that doesn't always make sense).
For some idea of what is needed, check out: https://github.com/JeffBezanson/FixedPointNumbers.jl https://github.com/JuliaDiff/DualNumbers.jl You also might check out the @delegate macro in DataStructures.jl: https://github.com/JuliaLang/DataStructures.jl/blob/master/src/delegate.jl https://github.com/JuliaLang/DataStructures.jl/blob/master/src/default_dict.jl#L52-L54 As for why this isn't more straightforward, check out the section of the docs on Types (especially the 4th paragraph): http://docs.julialang.org/en/release-0.4/manual/types/#types That said, I'm curious how you would define a new bitstype (Int, Float, etc.) in other languages? In Julia, this is at least possible, and when you define the things you need, these are as first class and efficient as Int, Float64, etc. (Of course, using them with non-Julia libraries might not work if these types don't exist in the language those libraries were written in.) In fact, all of these (Int64, Float64, etc.) are defined in Julia--none are actually "built-in", so to speak. As far as I know, there are very few other languages which allow you to define types at this level. (Examples, anyone?) Anyway, good luck in your explorations! Cheers, Kevin On Sat, Jun 11, 2016 at 8:42 AM, Jeffrey Sarnoff <[email protected]> wrote: > This way of which you speak, there are whispers ... Let me become strong > with milk of Yak, for I must swim with the Platypus of Insight as dawn is > drawn from glimmer to glisten. > ... . .... ..... ..... ...... ... .. . (writing becomes written) > > > On Saturday, June 11, 2016 at 11:09:34 AM UTC-4, Kevin Kunzmann wrote: >> >> Taking your last example to the console, still I cannot add two >> "Probabilities" despite them being instances of a subtype of "Real". What I >> was looking for is the Julian way of thinking about inherited behaviour >> from numeric types. Now, I slowly wrap my mind around the idea that there s >> nothing to inherit... >> But srsly, is there no way of making all functions that accept Reals also >> accept Probabilities? I can't reimplement them all, can I? Think of *(a,b), >> sin(a), /(a,b) >> >> On Saturday, 11 June 2016 09:40:38 UTC+2, Jeffrey Sarnoff wrote: >>> >>> , as 'Real' is expecting it to be named 'val'? Jeez, >>> >>> No, Real is an abstract type that is closer to being a label sewn to the >>> root of a tree -- Real does not have any investment in how you name the >>> fields of your type. >>> >>> There is no way of telling which fileds are accessed how by all methods >>>> operating on that type x >>> >>> One scenario, you designed the type and determine the sorts of >>> information to be held as fields of the type. You write specializations of >>> generic methods that pertain to using the type. In that situation, your >>> actively maintained documentation knows and tells or you revisit your own >>> source code for that knowledge. In any event, Julia is happy to help, >>> providing you with easily introduced method specific notes. Another >>> scenario, you did the same thing and I want to use the type. Well, I'd >>> look at the README.md file and if any, other docs. Then, knowing the care >>> you take with programming, and seeing from a few simples examples you >>> provide that values of this Probability type are floating point >>> representations of independent likelihoods ... >>> I would use the type without any desire to know which field(s) are read >>> or altered in the process of determining the probability than any one of my >>> five experts in origami will hand me a paper swan to drop from up here >>> before the building closes. >>> >>> the cleanest way to ensure that I pass a valid probability to my >>>> function (figure between 0 and 1) >>> >>> Do you want to raise an exception if a value is neither zero nor one nor >>> between zero and one? >>> Do you want to clamp negative values to zero and clamp positive values >>> above one to one? >>> Or do you want to clamp values that are within, say, -1//4096 .. >>> +4097//4096, and throw an exception outside of that range? >>> >>> (in this circumstance, for 'type' use 'immutable' and your typed values >>> will live and move in memory just like Float64 values. without interposed >>> indiirection.) >>> >>> immutable Probability >>> val::Float64 >>> >>> Probability(val::Float64) = ( 0.0 <= val <= 1.0 ) ? new(val) : >>> throw(ErrorException("Probabilities must be within 0..1")) >>> end >>> >>> (do you prefer the field name 'p' and to clamp the value?) >>> >>> immutable Probability >>> p::Float64 >>> >>> Probability(p::Float64) = new( max(0.0. min(p, 1.0)) ) >>> end >>> >>> Probability{T<:Real}(x::T) = Probability( convert(Float64, x) ) >>> >>> >>> >>> >>> On Saturday, June 11, 2016 at 1:54:42 AM UTC-4, Kevin Kunzmann wrote: >>>> >>>> Hey, >>>> >>>> thanks for sticking with me ;) >>>> >>>> I am, however, a little bit confused now (seems that oo and parallelism >>>> are the hardest to grasp in julia). >>>> >>>> I see that '+' was a bad example. So my error was, that I did not name >>>> the field correctly, as 'Real' is expecting it to be named 'val'? Jeez, if >>>> this is true then how is one ever going to 'inherit correctly' from a >>>> complicated abstract type? There is no way of telling which fileds are >>>> accessed how by all methods operating on that type x) >>>> >>>> So, put simply: What is the Julia way of ensuring that I pass a valid >>>> probability to my function (figure between 0 and 1). Please do not tell me >>>> that I am supposed to use @assert statements x) >>>> I would feel that a new type would be the cleanest way to do so? >>>> >>>> Best, >>>> >>>> Kevin >>>> >>>> On Saturday, 11 June 2016 04:37:32 UTC+2, Jeffrey Sarnoff wrote: >>>>> >>>>> Hi Kevin, >>>>> >>>>> Right questions, different way. >>>>> >>>>> Julia's type system is >>>>> of shared behavior for sharing behaviors. >>>>> for specialization as constructive delegation >>>>> >>>>> Real is an abstract type that is supertype to some other abstract >>>>> types >>>>> (Integer, Rational, FloatingPoint, FixedPoint, Probability, ...). >>>>> >>>>> [all kinds of] >>>>> >>>>> Each immediate subtype of the Real is an abstract type that is >>>>> supertype to some type[s]. >>>>> For every individual immediate subtype of Real, that individual is >>>>> supertype to abstract types and/or/orelse to concrete types. >>>>> Bool <: >>>>> Integer <: Real >>>>> Union{ Int32, Int64 } <: Signed <: Integer <: >>>>> Real >>>>> Union{ Rational{Int32}, Rational{Int64} } <: Rational <: Real >>>>> >>>>> *note that ..currently.. there is not* Integer <: >>>>> Rational <: Real, >>>>> as ..currently.. all type-based inheritance may associate a >>>>> concrete type with an abstraction >>>>> and that abstraction may be elaborated as a long chain >>>>> linking single supertypes >>>>> or may associate a concrete type with the concretion of >>>>> concrete constituents given as its field's types >>>>> orelse carry some of both manner of information, an enfolding >>>>> of the elaborative and the constitutive. >>>>> >>>>> in the early Summer of 2016: >>>>> Single inheritance of abstract type, and an inheriting abstract >>>>> type may itself be inherited. >>>>> One single inheritance of an abstract type by a Concrete type, >>>>> and the same, jointly or independently for each of its >>>>> concretely typed fields. >>>>> Any type, abstract or concrete can be defined with one or more >>>>> parameters (a parameterized type), >>>>> each distinct value(s of the tuple) of the parameter >>>>> constitutes a uniquely defined type, >>>>> there is support for specifying manner of co-action and >>>>> interaction for parameterized type 'siblings', >>>>> as there is for specifying the interworking of types and >>>>> intraworkings of values of a single type. >>>>> >>>>> The architects know how to let abstract types be functionally >>>>> dispatchable into, just as sqrt(x::Int64) and sqrt(x::Float64) are >>>>> dispatched into specializations of sqrt() for a Int64 or for a Float64 >>>>> argument. >>>>> The mechanism is being rethought so that a better, more widely useful >>>>> way obtain (does this and makes >>>>> it easy to process with and fully support software interface protocols >>>>> -- and enforce api constraints). >>>>> >>>>> Meanwhile "inheriting from Real" does give the type fallback >>>>> processing for basic mathematical handling, >>>>> and also encourages some reimplementation, if only to delegate the >>>>> calculation to the type's value field. >>>>> Multiplying two probabilities as reals gives a result that smaller >>>>> than either (or equal to smaller of the two), >>>>> which is not what happens to the probability of a win when more >>>>> skilled players join in the effort. >>>>> >>>>> Enjoy, >>>>> >>>>> Jeffrey >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> There is desire and activity intending >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> which is not the same as red marbles are a color of Marbleness >>>>> sculpted of a Material inheritance. >>>>> types >>>>> Integers are Real, Rationals are Real Integers are not >>>>> Rationals >>>>> >>>>> >>>>> (you are reading how it is >>>>> >>>>> On Fri, Jun 10, 2016 at 6:15 PM, Kevin Kunzmann <[email protected]> >>>>> wrote: >>>>> >>>>>> Hey Jeffrey, >>>>>> >>>>>> it's been a while, thx for the answer. I see that this would be >>>>>> working. However, what about min, max, sin, etc.? I do not want to >>>>>> re-implement all elementary functions for the Probability type. There >>>>>> must >>>>>> be some way to inherit the behaviour of the abstract supertype "Real". I >>>>>> guess I am missing something fundamental about the type system here. >>>>>> >>>>>> I felt tat something like >>>>>> >>>>>> type Probability{T<:Real} <:Real >>>>>> p::T >>>>>> end >>>>>> >>>>>> import Base.convert >>>>>> >>>>>> convert{T<:Real}(::Type{T}, x::Probability) = convert(T, x.p) >>>>>> convert{T1<:Real, T2<:Real}(::Type{Probability{T1}}, x::T2) = >>>>>> Probability(convert(T1, x)) >>>>>> >>>>>> >>>>>> should do the job as now any Probability can be converted to any >>>>>> concrete subtype of Real and "+" shoud be implemented there ;) >>>>>> Very strange, how does Julia handle inheritance at all??? >>>>>> >>>>>> Best, >>>>>> >>>>>> Kevin >>>>>> >>>>>> >>>>>> On Monday, 29 February 2016 23:45:35 UTC+1, Jeffrey Sarnoff wrote: >>>>>>> >>>>>>> Kevin, >>>>>>> >>>>>>> If all that you ask of this type is that it does arithmetic, clamps >>>>>>> any negative values to zero, and clamps any values greater than one to >>>>>>> one, >>>>>>> that is easy enough. Just note that arithmetic with probabilities >>>>>>> usually >>>>>>> is more subtle than that. >>>>>>> >>>>>>> import Base: +,-,*,/ >>>>>>> >>>>>>> immutable Probability <: Real >>>>>>> val::Float64 >>>>>>> >>>>>>> Probability(x::Float64) = min(1.0, max(0.0, x)) >>>>>>> end >>>>>>> >>>>>>> (+){T<:Probability}(a::T, b::T) = Probability( a.val + b.val ) >>>>>>> (-){T<:Probability}(a::T, b::T) = Probability( a.val - b.val ) >>>>>>> (*){T<:Probability}(a::T, b::T) = Probability( a.val * b.val ) >>>>>>> (/){T<:Probability}(a::T, b::T) = Probability( a.val / b.val ) >>>>>>> >>>>>>> You need conversion and promotion if you want to mix Float64 values >>>>>>> and Probability values: 2.0 * Probability(0.25) == Probability(0.5). >>>>>>> >>>>>>> On Sunday, February 28, 2016 at 10:33:07 AM UTC-5, Kevin Kunzmann >>>>>>> wrote: >>>>>>>> >>>>>>>> Hey, >>>>>>>> >>>>>>>> I have a (probably) very simple question. I would like to define >>>>>>>> 'Probability' as a new subtype of 'Real', only with the additional >>>>>>>> restriction that the value must be between 0 and 1. How would I achieve >>>>>>>> that 'Julia-style'? This should be possible without having to rewrite >>>>>>>> all >>>>>>>> these promotion rules and stuff, is it not? >>>>>>>> >>>>>>>> Best Kevin >>>>>>>> >>>>>>> >>>>>
