Tech Off Thread

15 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

A Few Ideas: ANumber & "Branded" Types

Back to Forum: Tech Off
  • User profile image
    Adam​Speight2008

    Idea 1: Numeric.ANumber

    In .net 4.0 Microsoft is introducing the BigInteger Type. Why didn't they also add the an arbitary precision type as well?

    They have shown previous they capability to implement one, as shown in the XP Powertoy PowerCalc. (Upto 512 digits).

    My reasoning is this, if it as extracted and available, coders wouldn't have to worry about parsing into a particalur type.

    To a end user; they enter a number, they ain't fussed wether it's a byte, a double or an integer.

     

    Namespace: Numerics.Number / Numerics.ANumber ← My Preference

    VB.Net Code Example:

    Dim x As ANumber=123.567

    Dim NewPrice As ANumber = ANumber.FromText(ProductPriceChange.NewPrice)

    Note: Number.FromText can accept strings, or any control that has text propertity, etc,

    ThisNumber.Increment

    ThisNumber.Decrement

    While ThisNumber.IsPositive (Note: IsPositive, Zero is classified as a positive.)

    To me this further enhances the readabilty of the codesource.

    For it to be as useful as the standard base class types, it would require to have the full functionality of System.Math.

    Or its own NameSpace: Numeric.ANumber.Math /  Numerics.Math

     

    Idea 2: "Branded" Types

    To have the ability to "brand" an instance of a numeric type (BaseClass & Numeric) as of belong to a particular user-define "collection" or unit.

    Think of it as an opposite to Generics but a type gets "Branded".

    Then Functions, Methods, etc. that take "branded" type only accept those "branded types".Saving the coder have to implement explicitly as new class. Also it would let enable the capabilty of being checked at design / compile time. Minimising and catching some of the basic human errors. I.e. Confusing Feet & Inchs with metres.

    VB.Net Code Example:

    Dim CarSpeed As Double [Velocity] Note: Using Square Braces My Preference

    Dim CarSpeed As Double {AsA Velocity} Note: Keyword "AsA"


    Function ImpactSpeed(ByRef v1 As Double[Velocity], ByRef v2 As Double[Velocity] ) As Double[Velocity]

    Dim Vi As Double[Velocity]

    Vi=v1+v2

    Return Vi

    End Function

     

    Intellisense could then be extended to have the capabilty show the coder all the "Branded" types.

    Dim  MassOfThisPerson As Double[→Velocity ?]

    In addition to letting the coder create a "brand" Microsoft could supply a predefined list of "Branded" types for example, covering SI units of measurement (Mass, Velocity)

     

    What are your thoughts on these ideas?

     

  • User profile image
    Sven Groot

    While ThisNumber.IsPositive (Note: IsPositive, Zero is classified as a positive.)

    How is that more readable or more clear than just "While ThisNumber >= 0"?

    And making IsPositive include 0 is just weird and counter-intuitive. If you must have a property like that, at least call it IsNotNegative if it's meant to include zero (precedent: XSD data types can have an isPositive constraint (larger than zero) or isNotNegative constraint (larger than or equals zero)).

  • User profile image
    AndyC

    Sven Groot said:

    *snip*

    How is that more readable or more clear than just "While ThisNumber >= 0"?

    And making IsPositive include 0 is just weird and counter-intuitive. If you must have a property like that, at least call it IsNotNegative if it's meant to include zero (precedent: XSD data types can have an isPositive constraint (larger than zero) or isNotNegative constraint (larger than or equals zero)).

    AdamSpeight2008 said:
    My reasoning is this, if it as extracted and available, coders wouldn't have to worry about parsing into a particalur type.
    Well, they would. Arbitrary precision arithmetic is slow, it's not something you'd want to be using all the time. I'm not saying it wouldn't be a good addition, but I'm not sure it's needed all that much. It certainly isn't (or shouldn't be) a general purpose solution to storing numbers.

    "Branding" - Not sure this really gives you much over inheritance, except it the case of sealed classes perhaps. It's probably something that you could do with Attributes in the rare cases that it really mattered.

  • User profile image
    Curt Nichols

    > Why didn't they also add the an arbitrary precision type as well?

    My take on this is a) you're not thinking like a business, and b) product teams don't have infinite resources, even at Microsoft--there are probably better things for them to spend their time on.

    I have seen Eric Lippert respond a number of times to the question "Why wasn't feature X implemented?" A couple of his public posts that touch on the topic: How many Microsoft employees does it take to change a lightbulb? and In Foof We Trust: A Dialogue.

    (Eric's blog covers many topics, and has some good series on immutability and covariance/contravariance. One could do a lot worse than to read his blog regularly.)

  • User profile image
    Matthew van Eerde

    Sven Groot said:

    *snip*

    How is that more readable or more clear than just "While ThisNumber >= 0"?

    And making IsPositive include 0 is just weird and counter-intuitive. If you must have a property like that, at least call it IsNotNegative if it's meant to include zero (precedent: XSD data types can have an isPositive constraint (larger than zero) or isNotNegative constraint (larger than or equals zero)).

    while (!ThisNumber.IsNegative) I could see.

    Under duress I might go along with while (ThisNumber.IsNonNegative).

    IsNotFoo properties rub me the wrong way.  Too much chance of double negation.

  • User profile image
    Adam​Speight2008

    Sven Groot said:

    *snip*

    How is that more readable or more clear than just "While ThisNumber >= 0"?

    And making IsPositive include 0 is just weird and counter-intuitive. If you must have a property like that, at least call it IsNotNegative if it's meant to include zero (precedent: XSD data types can have an isPositive constraint (larger than zero) or isNotNegative constraint (larger than or equals zero)).

    While ThisNumber>=0

    To me this is comparing ThisNumber's value with 0 (A potentially expensive depending how the comparater was coded).

    While ThisNumber.IsPositive

    Whereas ths is a check of the sign of the number (Testing if something is set), There is nothing stopping adding .IsNegative or .Zero

    Why I include 0 as a positive number? I was thinking about collections indexs. Consider the printing contents of collection.

    Dim x As ANumber=99 : While x.IsPositive: Print Element(x) : x.Decrement ; End While

     

    My point is that they already have the code for Arbitrary precision arithmetic (APA) It's not like starting from scratch.

    I know A.P.A. are slow but it would have better to have had the choice to use it or not.

     

    Regarding "Branded" I think you may have missed the important point about "Branded" Types, they are checked at Design/Compile Time not run time.

    Dim Name1 As String["Name"]="Adam"

    Dim Name2 As String["Name"]="Paul"

    Dim Street1 As String["Street"]="Doe Road"

    Dim String As String["Street"]="Doe Road"

    Traditional if you wrote: If Name1=Street1 Then Compiler would let it through

    With "Branded" Type: If Name1=Street1 Then  the Compiler would complain.

    Dim TimeTaken As Double["Seconds"] = 10

    Dim Distance As Double["Metres"]=5

    Dim v1 As Double["SpeedMs"]

    v1=Distance / TimeTaken 'Compiler Warning (Possible Issue): Division of Mismatched Branded Types.

    One Possible way to dismiss the Compiler Warning. Is to extend "Branded" type so rules apply rules them.

    Public Brands

     Double[Metres]

     Double{Seconds]

     Double[Speed_MperS]

    End Brands

    Public BrandRules

     Double[Speed_MperS] :=Double[Metre] / Double[Seconds]

    End BrandRules

    So by adding the above, to warning vanishes, but v1=TimeTaken / Distance throws an warning.

  • User profile image
    W3bbo

    AdamSpeight2008 said:
    Sven Groot said:
    *snip*

    While ThisNumber>=0

    To me this is comparing ThisNumber's value with 0 (A potentially expensive depending how the comparater was coded).

    While ThisNumber.IsPositive

    Whereas ths is a check of the sign of the number (Testing if something is set), There is nothing stopping adding .IsNegative or .Zero

    Why I include 0 as a positive number? I was thinking about collections indexs. Consider the printing contents of collection.

    Dim x As ANumber=99 : While x.IsPositive: Print Element(x) : x.Decrement ; End While

     

    My point is that they already have the code for Arbitrary precision arithmetic (APA) It's not like starting from scratch.

    I know A.P.A. are slow but it would have better to have had the choice to use it or not.

     

    Regarding "Branded" I think you may have missed the important point about "Branded" Types, they are checked at Design/Compile Time not run time.

    Dim Name1 As String["Name"]="Adam"

    Dim Name2 As String["Name"]="Paul"

    Dim Street1 As String["Street"]="Doe Road"

    Dim String As String["Street"]="Doe Road"

    Traditional if you wrote: If Name1=Street1 Then Compiler would let it through

    With "Branded" Type: If Name1=Street1 Then  the Compiler would complain.

    Dim TimeTaken As Double["Seconds"] = 10

    Dim Distance As Double["Metres"]=5

    Dim v1 As Double["SpeedMs"]

    v1=Distance / TimeTaken 'Compiler Warning (Possible Issue): Division of Mismatched Branded Types.

    One Possible way to dismiss the Compiler Warning. Is to extend "Branded" type so rules apply rules them.

    Public Brands

     Double[Metres]

     Double{Seconds]

     Double[Speed_MperS]

    End Brands

    Public BrandRules

     Double[Speed_MperS] :=Double[Metre] / Double[Seconds]

    End BrandRules

    So by adding the above, to warning vanishes, but v1=TimeTaken / Distance throws an warning.

    I think what you're after with your "branded" types is some kind of Strong-Typed Aliasing which echos a particular use case of C's #DEFINE blocks.

    C# already allows the aliasing of types, but not in any meaningful way (You can already do "using Metre = System.Int32;" and then use Metre as if it were Int32). Pop an email down to the compiler folks if you think you've got a case.

  • User profile image
    Adam​Speight2008

    Aliasing In VB.net

      Imports Metres = Double

     Imports Seconds = Double

     Imports Speed = Double

     

     Public Function CalcSpeed(ByRef d As Metres, ByRef s As Metres) As Speed

     Return d/s

     End Function

     

     Dim m As Metres=100

     Dim s As Seconds=9.98

     v1=CalcSpeed(m,s) OK but v1=CalcSpeed(s,m)  Compiles! Wrong

  • User profile image
    Matthew van Eerde

    AdamSpeight2008 said:
    Sven Groot said:
    *snip*

    While ThisNumber>=0

    To me this is comparing ThisNumber's value with 0 (A potentially expensive depending how the comparater was coded).

    While ThisNumber.IsPositive

    Whereas ths is a check of the sign of the number (Testing if something is set), There is nothing stopping adding .IsNegative or .Zero

    Why I include 0 as a positive number? I was thinking about collections indexs. Consider the printing contents of collection.

    Dim x As ANumber=99 : While x.IsPositive: Print Element(x) : x.Decrement ; End While

     

    My point is that they already have the code for Arbitrary precision arithmetic (APA) It's not like starting from scratch.

    I know A.P.A. are slow but it would have better to have had the choice to use it or not.

     

    Regarding "Branded" I think you may have missed the important point about "Branded" Types, they are checked at Design/Compile Time not run time.

    Dim Name1 As String["Name"]="Adam"

    Dim Name2 As String["Name"]="Paul"

    Dim Street1 As String["Street"]="Doe Road"

    Dim String As String["Street"]="Doe Road"

    Traditional if you wrote: If Name1=Street1 Then Compiler would let it through

    With "Branded" Type: If Name1=Street1 Then  the Compiler would complain.

    Dim TimeTaken As Double["Seconds"] = 10

    Dim Distance As Double["Metres"]=5

    Dim v1 As Double["SpeedMs"]

    v1=Distance / TimeTaken 'Compiler Warning (Possible Issue): Division of Mismatched Branded Types.

    One Possible way to dismiss the Compiler Warning. Is to extend "Branded" type so rules apply rules them.

    Public Brands

     Double[Metres]

     Double{Seconds]

     Double[Speed_MperS]

    End Brands

    Public BrandRules

     Double[Speed_MperS] :=Double[Metre] / Double[Seconds]

    End BrandRules

    So by adding the above, to warning vanishes, but v1=TimeTaken / Distance throws an warning.

    > Why I include 0 as a positive number? I was thinking about collections indexs.

    Formally, 0 is neither positive nor negative, so .IsPositive is confusing.  >= 0 is the simplest way to get what you want across, I think.

  • User profile image
    Adam​Speight2008

    Have a workable solution (code below) for "Branded" that works in VS2010, lacks the syntactic sugar of the idea base.

    Maybe someone can help to add that, so that

    Dim _M As Double["Metres"]=100

    Function(ByVal _Distance As Double["Meters"],ByVal _TimeTaken[Seconds])

    is converted to

    Dim _M As New Brand(of Double)(100,"Metres")

    Function(ByVal _Distance As Brand(Of Double), ByVal _TimeTaken As Brand(Of Double))

      Contracts.Contract.RequiresAlways(_Distance.Brand.ToUpper = "METERS")
      Contracts.Contract.RequiresAlways(_TimeTaken.Brand.ToUpper = "SECONDS")

    Respectively

    The workable solution code

    Module BrandedTest

     Sub Main()

       Dim dist As New Brand(Of Double)(100, "Meters")
    Dim t As New Brand(Of Double)(9.98, "Seconds")
         Dim v1 As Brand(Of Double) = Test(dist, t)

     Dim v2 As Brand(Of Double) = Test(t, dist) 'Doesn't Compile which is great

     

      End Sub

    Public Function Test(ByVal _Distance As Brand(Of Double), ByRef _TimeTaken As Brand(Of Double)) As Brand(Of Double)
        Contracts.Contract.RequiresAlways(_Distance.Brand.ToUpper = "METERS", "Distance value isn't in Metres")
        Contracts.Contract.RequiresAlways(_TimeTaken.Brand.ToUpper = "SECONDS", "TimeTaken value isn't in Seconds")
        Return New Brand(Of Double)(_Distance.Value / _TimeTaken.Value, "Speed (MperSec)")
      End Function

    End Module

     Public Class Brand(Of T)
       Protected m_Value As T
       Public Property Value() As T
         Get
           Return m_Value
         End Get
         Set(ByVal value As T)
           m_Value = value
         End Set
       End Property
     
       Protected m_Name As String = ""
       Public ReadOnly Property Brand() As String
         Get
           Return m_Name
         End Get
       End Property
     
       Public Sub New(ByVal v As T, ByVal Name As String)
         m_Value = v
         m_Name = Name
       End Sub
     
      Shared Function SameBrand(ByVal _A As Brand(Of T), ByVal _B As Brand(Of T)) As Boolean
        Return _A.Brand.CompareTo(_B) = 0
      End Function
     End Class

  • User profile image
    TommyCarlier

    AdamSpeight2008 said:

    Have a workable solution (code below) for "Branded" that works in VS2010, lacks the syntactic sugar of the idea base.

    Maybe someone can help to add that, so that

    Dim _M As Double["Metres"]=100

    Function(ByVal _Distance As Double["Meters"],ByVal _TimeTaken[Seconds])

    is converted to

    Dim _M As New Brand(of Double)(100,"Metres")

    Function(ByVal _Distance As Brand(Of Double), ByVal _TimeTaken As Brand(Of Double))

      Contracts.Contract.RequiresAlways(_Distance.Brand.ToUpper = "METERS")
      Contracts.Contract.RequiresAlways(_TimeTaken.Brand.ToUpper = "SECONDS")

    Respectively

    The workable solution code

    Module BrandedTest

     Sub Main()

       Dim dist As New Brand(Of Double)(100, "Meters")
    Dim t As New Brand(Of Double)(9.98, "Seconds")
         Dim v1 As Brand(Of Double) = Test(dist, t)

     Dim v2 As Brand(Of Double) = Test(t, dist) 'Doesn't Compile which is great

     

      End Sub

    Public Function Test(ByVal _Distance As Brand(Of Double), ByRef _TimeTaken As Brand(Of Double)) As Brand(Of Double)
        Contracts.Contract.RequiresAlways(_Distance.Brand.ToUpper = "METERS", "Distance value isn't in Metres")
        Contracts.Contract.RequiresAlways(_TimeTaken.Brand.ToUpper = "SECONDS", "TimeTaken value isn't in Seconds")
        Return New Brand(Of Double)(_Distance.Value / _TimeTaken.Value, "Speed (MperSec)")
      End Function

    End Module

     Public Class Brand(Of T)
       Protected m_Value As T
       Public Property Value() As T
         Get
           Return m_Value
         End Get
         Set(ByVal value As T)
           m_Value = value
         End Set
       End Property
     
       Protected m_Name As String = ""
       Public ReadOnly Property Brand() As String
         Get
           Return m_Name
         End Get
       End Property
     
       Public Sub New(ByVal v As T, ByVal Name As String)
         m_Value = v
         m_Name = Name
       End Sub
     
      Shared Function SameBrand(ByVal _A As Brand(Of T), ByVal _B As Brand(Of T)) As Boolean
        Return _A.Brand.CompareTo(_B) = 0
      End Function
     End Class

    F# has support for “units of measure” which is basically the same as your “branding”, but much more advanced: you can calculate with units of measure. See this blog post by Andrew Kennedy.

  • User profile image
    Yggdrasil

    I like the Branded types idea, although I prefer the name Alias or Typedef or something like that. I like the idea because it's like a simple contractual interface, not of syntax but of intent. This is the reason I don't like using generic Tuple<X,Y> and prefer to subclass it - explicitness.

  • User profile image
    Adam​Speight2008

    Yggdrasil said:

    I like the Branded types idea, although I prefer the name Alias or Typedef or something like that. I like the idea because it's like a simple contractual interface, not of syntax but of intent. This is the reason I don't like using generic Tuple<X,Y> and prefer to subclass it - explicitness.

    That's the idea a simple contractual Interface to express an intent, which in case it could do with a different name.

    I think changing it from Brand(Of  to Use(Of should make it clearer , as its designed to check the intend useage.
    .Brand => .DefinedAs

     

  • User profile image
    spivonious

    AdamSpeight2008 said:
    Yggdrasil said:
    *snip*

    That's the idea a simple contractual Interface to express an intent, which in case it could do with a different name.

    I think changing it from Brand(Of  to Use(Of should make it clearer , as its designed to check the intend useage.
    .Brand => .DefinedAs

     

    What happens if you want to change an address to an array of 3 strings? String[address] no longer makes sense then.

    I also think the whole idea isn't saving anything. The variable name should tell me what the value is, not the type. If I see speed = distance / time, I say "yep, makes sense." If I see speed = time / distance, I don't need the compiler to tell me something is wrong.

  • User profile image
    Adam​Speight2008

    spivonious said:
    AdamSpeight2008 said:
    *snip*

    What happens if you want to change an address to an array of 3 strings? String[address] no longer makes sense then.

    I also think the whole idea isn't saving anything. The variable name should tell me what the value is, not the type. If I see speed = distance / time, I say "yep, makes sense." If I see speed = time / distance, I don't need the compiler to tell me something is wrong.

    "What happens if you want to change an address to an array of 3 strings? String[address] no longer makes sense then."

    Dim Adresss(2) As String[Address]

     

    "If I see speed = time / distance, I don't need the compiler to tell me something is wrong."

    You completely missed the the point. At the moment you can a have a function with parameters of the same type.

     

    You could unknowning supply the them in the wrong. and you  won't know you had until you ran it where the program performs incorrectly. Whereas if you "Branded" the instantion of the types it would have bean caught at compile time.

    Function Foo(Byval A As Double, ByVal B As Double) As Boolean

    End Function

    ' "Branded"

    Function Foo(ByVal A As Double[Type_A], ByVal B As Double[Type_B]) As Boolean

    End Function

     

    Dim A As Double

    Dim B AS Double

    Dim AB As Double[Type_A]

    Dim BB As Double[Type_B]

     All the variable-based input combinations of variable iputs that can be supplied to the Functon Foo

    Foo(A,A) Foo(A,B) Foo(A,AB) Foo(A,BB)

    Foo(B,A) Foo(B,B) Foo(B,AB) Foo(A,BB)

    Foo(AB,A) Foo(AB,B) Foo(AB,AB) Foo(AB,BB)

    Foo(BB,A) Foo(BB,B) Foo(BB,AB) Foo(BB,BB)

     With "Brand" types only the Bolded combination is allowed, without them all are all valid inputs.

     

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.