3

Background

I am writing a managed x64 assembler (which is also a library), so it has multiple classes which define an unsigned 64-bit integer property for use as addresses and offsets. Some are file offsets, others are absolute addresses (relative to the main memory) and again others are relative virtual addresses.

Problem

I use the ulong datatype for the properties in the mentioned scenarios, and this works fine. However, such properties are not CLS-compliant. I can mark them as [ClsCompliant(false)], but then I need to provide a CLS-compliant alternative to users of the library.

Options and questions

Some suggest providing an alternative property with a bigger data type, but this is not an option because there is no bigger signed integer primitive which could hold all values from 0 to UInt64.MaxValue.

I would rather not mark my entire assembly as non-CLS-compliant, because in most usage scenario's, not all the possible values up to UInt64.MaxValue are used. So, for e.g. Address I could provide an alternative long property AddressAlternative, which only accepts positive values. However, what should happen when Address somehow contains a value above Int64.MaxValue. Should AddressAlternative throw some exception?

And what would be an appropriate name for AddressAlternative?

Providing an alternative for every usage of ulong would result in many 'double' properties. Is there a better way to do this? Note that not all usages of ulong properties have the same semantics, so a single struct would not cut it.

And finally, I have the same CLS compliance problem in constructor parameters. So should I provide an alternative overload accepting long for such a parameter?

I do not mind restricting the use of (some functionality) of the library when it is used from a CLS-only context, as long as it can be used in most scenarios.

Community
  • 1
  • 1
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • 1
    Do you anticipate having a lot of users of this library who are using languages that require strict CLS compliance? How many customers do you have who will be using the library from a language that doesn't have support for ulong? – Eric Lippert Apr 05 '11 at 16:48
  • 5
    Your comment that "not all usages of ulong properties have the same semantics, so a single struct would not cut it" seems to hold a possible solution. If, say, offsets and addresses have different semantics then why not make an Offset and and Address struct that are wrappers around a ulong, that enforce whatever semantics you want? You can even have overloaded operators, so that an Address + Address is illegal, but Address + Offset makes a new Address. – Eric Lippert Apr 05 '11 at 16:50
  • 1
    It will be open-source, so that depends on the availability of strict CLS languages. CLS compliance is very much [advised](http://stackoverflow.com/questions/1828575/why-should-i-write-cls-compliant-code) when writing a library. – Daniel A.A. Pelsmaeker Apr 05 '11 at 16:52
  • Indeed, it answers some of my questions. But wouldn't that cause a lot of code duplication? I know of at least three different semantic types where ulong is used. And then I move the problem to the new Address type: it will contain some property which can return the current address value, but when it represents an unsigned address above Int64.MaxValue, what should the alternative property return? – Daniel A.A. Pelsmaeker Apr 05 '11 at 16:55
  • @Virtlink Could you use BigInteger from System.Numerics? http://msdn.microsoft.com/en-us/library/dd268220.aspx – Michael Stum Apr 05 '11 at 17:46
  • 1
    @Virtlink: I think that using "semantic structs", as Eric has suggested, is the way to go here. That said I don't think you should have any properties on them at all - just provide conversion operators: explicit conversion from `ulong` and `decimal`, and implicit conversion to `ulong` and `decimal`. Why `decimal`? It is the only other standard type that covers the entire range of `ulong` with no loss of precision, and you can easily do checks for no fractional part. – Pavel Minaev Apr 05 '11 at 18:14
  • @EricLippert Could you make your comment into an answer? I'd like to accept it. – Daniel A.A. Pelsmaeker Jul 27 '12 at 22:47

2 Answers2

2

but when it represents an unsigned address above Int64.MaxValue

You are using the wrong type, addresses must be stored in IntPtr or UIntPtr. There is just no way your problem is realistic. If you can't afford to lose the single bit in UInt64 then you are way too close to overflow. If this number represents an index then a plain Int32 will be fine, .NET memory blobs are limited to 2 gigabyte, even on a 64-bit machine.

If it is an address then IntPtr will be fine for a very, very long time. Currently available hardware is 4.5 orders of magnitude away from reaching that limit. Very drastic hardware redesign will be needed to get close, you'll have much bigger problems to worry about when that day ever comes. Nine exabyte of virtual memory is enough for everybody until I retire.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • *Nine exabyte of virtual memory is enough for everybody until I retire*: are you sure? Bill Gates used to say the same thing about 640 kilobytes ;) (at least that's what the legend says...) – Thomas Levesque Apr 05 '11 at 18:03
  • 1
    Did you read the background information? I'm writing an x64 assembler, thus it needs support for 64-bit addresses. Those addresses are just 64-bit integers, correctly represented by an ulong. The application has nothing to do with .Net Framework addresses, so IntPtr is of no use to me. It is meant to produce an x64 binary, not some .Net executable code. – Daniel A.A. Pelsmaeker Apr 05 '11 at 18:16
  • What makes you think an assembler doesn't have the same restrictions as a compiler? This is a hardware issue. The notion of a CLS compliant assembler does tickle the fancy. So is the need for it to interact with .NET languages that don't support unsigned integers. They won't know how to handle the address either. – Hans Passant Apr 05 '11 at 18:28
  • 2
    Please look at it this way: I am just writing a library which must support and use ulong datatypes in that specific situation. The question is not about whether I am making the correct assumptions about the future. The question is: how am I going to provide a CLR-compliant alternative to the ulong properties. – Daniel A.A. Pelsmaeker Apr 05 '11 at 18:52
0

Microsoft defines a 64-bit address as Int64, not UInt64, so you can still be CLS compliant.

Please refer to http://msdn.microsoft.com/en-us/library/837ksy6h.aspx.

Which basically says:

IntPtr Constructor (Int64)

Initializes a new instance of IntPtr using the specified 64-bit pointer.

Parameters value Type: System.Int64 A pointer or handle contained in a 64-bit signed integer.

And yes, I just did a quick test and the following worked fine in a project targeted for either x64 or Any CPU. I placed a brekpoint in the code and examined x. However, when targeted for only x86, it will throw an exception.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IntPtr x = new IntPtr(long.MaxValue);
        }
    }
}

But, if it turns out that you really need that extra bit. You could provide two libraries. One that is CLS-Compliant and one that is not--user's choice. This could be accomplished by using #if statements and using Conditional Compilation Symbols. This way, you can define the same variable name, but with different definitions. http://msdn.microsoft.com/en-us/library/4y6tbswk.aspx

Community
  • 1
  • 1
Jim
  • 2,034
  • 1
  • 22
  • 43