1

How can such a function be created? (How do the framework do it for Chr) Or why is it not possible, but possible in the framework?

Example of consts declared from function:

''' <summary>Carriage Return \r 13 0xD</summary>
Public Const Cr As Char = ChrW(&HD)
''' <summary>Line Feed \n 10 0xA</summary>
Public Const Lf As Char = ChrW(&HA)

MS reference source for ChrW

So it should be possible to create similar functions ex:

Public Const Magic As String = "Magic" ' ok
Public Const lcMagic As String = Magic.ToLower ' not ok - wanted to avoiding potential bugs if Magic is ever changed.
Public Const Magic2 As String = functionGeneratingLongButStaticString()

A workaround for most cases is something like:

''' <summary>Lowercase value of Magic</summary>
Public Shared ReadOnly lcMagic As String = Magic.ToLower

But this do not provide intellisense of the actual value.
And not "secure" since it is possible to modify ReadOnly fields with reflection

So is there any way to declare 'const functions' at all, and if not, how do the framework really do it?

Edit: Checked the generated IL:

.field public static literal char Cr = char('\r')

Which means it is a special case for the compiler.

Community
  • 1
  • 1
NiKiZe
  • 1,256
  • 10
  • 26
  • 1
    a const cant be the result of a function or expression. they have to be known at compile time which is not be the case when trying to assign the result of something. – Ňɏssa Pøngjǣrdenlarp Sep 22 '14 at 17:38
  • Look at the docs: [You cannot use variables or functions in initializer. However, you can use conversion keywords such as CByte and CShort. You can also use AscW if you call it with a constant String or Char argument, since that can be evaluated at compile time.](http://msdn.microsoft.com/en-us/library/cyxe49xw.aspx). – Bjørn-Roger Kringsjå Sep 22 '14 at 17:42
  • Yes all this is about (wanted) compiletime evaluation, so how is it that `Chr` (only for 0 - 127), `Asc` and its friends can be called on compiletime and used as `Const`. Since `Const Cr As Char = ChrW(&HD)` works and `ChrW` [is a function](http://referencesource.microsoft.com/Microsoft.VisualBasic/R/6283a83f3afbfba9.html) "a const cant be the result of a function or expression" is not quite true. So the question remains, what is the magic behind these functions - and why is it not possible to create these "compiletime functions" ? – NiKiZe Sep 22 '14 at 17:53

2 Answers2

4

The compiler may be treating AscW and ChrW as special cases. A search of the Roslyn source code for "AscW" turns up the following in OptimizeLibraryCall (lots of code snipped for clarity):

            ' AscW(char) / AscW(String)
            ' all values can be optimized as a literal, except an empty string that produces a diagnostic
            If IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscWCharInt32, method) OrElse
                IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscWStringInt32, method) Then

                '[...]
                Return ConstantValue.Create(AscW(argumentValue))
            End If

            ' ChrW
            ' for -32768 < value or value > 65535 we show a diagnostic
            If IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__ChrWInt32Char, method) Then
                '[...]
                Return ConstantValue.Create(ChrW(argumentValue))
            End If

            '[...]

There's also a comment in EarlyWellKnownAttributeBinder.CanBeValidAttribute that specifically mentions AscW and ChrW in the types of compile-time constants that can be used for attribute values:

        ' 11.2 Constant Expressions
        '
        'A constant expression is an expression whose value can be fully evaluated at compile time. 
        ' [...]
        '         The following run-time functions:
        '            Microsoft.VisualBasic.Strings.ChrW
        '            Microsoft.VisualBasic.Strings.Chr, if the constant value is between 0 and 128
        '            Microsoft.VisualBasic.Strings.AscW, if the constant string is not empty
        '            Microsoft.VisualBasic.Strings.Asc, if the constant string is not empty

The Mono vbnc compiler seems to have an IsConstantMethod helper method to support these functions (it specifically checks whether the method is AscW, Asc, ChrW, or Chr), along with a test case specifically to test whether const statements accept those functions, which suggests they are special cases.

If you look at your compiled assembly in ildasm, you'll see:

.field public static literal char Cr = char(0x000D)

You can see that the compiler is evaluating the function and emitting the result -- it's not embedding any sort of "constant function" call, and there's not any sort of attribute decoration on those functions in the reference source that marks them as a "constant function".

So to answer your questions, it looks like the compiler does this by treating those string functions as special hardcoded cases, and it doesn't look like there's any way to do so, short of modifying the compiler code.

pmcoltrane
  • 3,052
  • 1
  • 24
  • 30
  • Thanks, Just diggd up the IL myself and saw the the generated literal +1 for providing references to source actually explaining this. For bonus points is it possible to write inline IL that can be used as Const? – NiKiZe Sep 22 '14 at 19:20
0

From MSDN:

You cannot use variables or functions in initializer. However, you can use conversion keywords such as CByte and CShort. You can also use AscW if you call it with a constant String or Char argument, since that can be evaluated at compile time.

ChrW etc are special because the compiler is designed to allow them:

Private Const vblf As String = ChrW(10)

Compiles to:

private const char vblf = '\n';

Most other forms using NET function are illegal:

Private Const vbcr As String = Convert.ToString(New Byte() {13})
Private Const vblf2 As Char = Environment.NewLine

Private Const Z As String = Ziggy.ToLower

Even if Ziggy is a constant, making it seem like it should be legal, the function result is not. The return could be different on a non-English system making for very nasty issues at runtime when strings do not match but should.

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • "the compiler is designed to allow them" was more or less the part I was missing. so the interesting part showed up when checking the IL, so the "Compiles to" C syntax is a bit confusing/misleading. – NiKiZe Sep 22 '14 at 19:41
  • it optimizes out the call to Chr and simply uses the return in the Const declaration. – Ňɏssa Pøngjǣrdenlarp Sep 22 '14 at 19:44