Generic List

Started by stanl, March 27, 2022, 05:07:21 AM

Previous topic - Next topic

stanl

As WB has array and map handling below is not a competition. But out of curiosity, why do generics behave differently than other collections
Code (WINBATCH) Select


;comment/uncomment to test
;objList = CreateObject("System.Collections.ArrayList")
;t="ArrayList


;objList = CreateObject("System.Collections.Hashtable")
;t="Hashtable"


objList = CreateObject("System.Collections.Queue")
t="Queue"
Message(t,objList)
objList=0


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;both these will fail - comment/uncomment to test
objList = CreateObject("System.Collections.Generic.List")
Message("Generic List",objList)
objList=0


;or using CLR
ObjectClrOption ( "useany", "System")
objList = ObjectClrNew('System.Collections.Generic.List')
Message("Generic List",objList)
objList=0


Exit

td

It has been stated many, many times over the last ~9 years that dotNet generics are not compatible with WIL's implementation of CLR hosting so it is a bit curious that the question gets asked at this late date. And the answer would be more or less self-evident with an in-depth understanding of the principles of generic programming.

[edit] Neglected to mention that forum member CCopp posted a fairly concise explanation of generic programming and WinBatch on this forum. It might be worth a search and read.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Quote from: td on March 27, 2022, 08:44:28 AM
so it is a bit curious that the question gets asked at this late date. And the answer would be more or less self-evident with an in-depth understanding of the principles of generic programming.


I probably asked the questions over last 9 years. Probably ask it again next year. It's the self-evident dig that is a little annoying... WB is a programming language - so generic programming is not programming? I'm facing an issue building on an ArrayList where a Generic.List would be more beneficial for memory and speed.  :o

td

I have no idea what you are referring to by "dig" but if I offended you please accept my apology. WIL is a programming language but it is also true that not all programming languages support the same syntax and programming language features. If that were the case, there would be only one programming language.

Generics are not supported by WIL nor are they ever likely to be. One of the reasons for this is covered in Chuch Chopp's post of a few years ago.



"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

ChuckC

i recall that long discussion.  In-memory compilation of C# code to produce a specialized instance of a generic type is still the best way to utilize .NET generics from within WIL.  And, as Tony mentioned, if WIL already has a built in type [e.g. maps] that is equivalent to a .NET generic type, then it's both expedient and likely to be more performant when using the built in types.

stanl

Quote from: ChuckC on March 28, 2022, 11:13:19 AM
i recall that long discussion.  In-memory compilation of C# code to produce a specialized instance of a generic type is still the best way to utilize .NET generics from within WIL. 


I tested that route after using one of Jim's in-memory scripts as a guide - didn't get that far. And agreed, Wil maps will be tried as the experience I have had with them left nothing to be desired. I was attracted to system.collections.generic.list because of the numerous methods like addrange() which I felt would fit with the task I am undertaking. And, calling PS code for a generic list is not in the cards do to the scope of the task.



ChuckC

PowerShell isn't required, per-se, to perform dynamic compilation of C# code, so your constraint of not utilizing PowerShell shouldn't be a factor.  PowerShell does, however, make it easier to create an instance of a generic container bound to specific key/value types without dynamic compilation of C# code.

td

It's a cheesy hack. It might still be entertaining for the curious...

Code (winbatch) Select
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;  CompileWbNameSpace
;;
;;  Performs an in-memory compilation of a .Net generic based class.
;;
;; returns 1 on succes; otherwise: aborts script on compiler errors.
;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#definefunction CompileWbNameSpace()
   objCSharp = ObjectClrNew("Microsoft.CSharp.CSharpCodeProvider")
   objParams = ObjectClrNew("System.CodeDom.Compiler.CompilerParameters")
   objParams.ReferencedAssemblies.Add("mscorlib.dll")
   objParams.GenerateInMemory = ObjectType( "VT_BOOL", 1 )
   cSharpSource = $"
using System;
using  System.Collections.Generic;
namespace WinBatch {
 
  // Part class lifted from an MSFT example.
  public class Part :: IEquatable<Part>
    {
        public string PartName { get; set; }
        public int PartId { get; set; }

        public override string ToString()
        {
            return "ID:: " + PartId + "   Name:: " + PartName;
        }
        public override bool Equals(object obj)
        {
            if (obj == null) return false;
            Part objAsPart = obj as Part;
            if (objAsPart == null) return false;
            else return Equals(objAsPart);
        }
        public override int GetHashCode()
        {
            return PartId;
        }
        public bool Equals(Part other)
        {
            if (other == null) return false;
            return (this.PartId.Equals(other.PartId));
        }
    // Should also override == and != operators.
   }

   // Parts list with a less than optimal implementation...
   public class PartsList  {   
      // Concrete instance of a generic using the Parts class.
      public static List<Part> aList =  new List<Part>();
     
      public List<Part> GetPartsList ()
      {
         return aList;
      }
      public void Add  (Part Item)
      {
         aList.Add(Item);
      }
      public int Count ()
      {
         return aList.Count;
      }
   }
}
;$"

   objResult = objCSharp.CompileAssemblyFromSource(objParams,cSharpSource)

   ; Shouldn't see any of this if the C# code is written correctly.
   strOutput = ''
   bError = 0
   If objResult.Output.Count > 0
      strOuput = 'Compiler Output: ':@lf
      For x = 0 To objResult.Output.Count-1
         If strOutput == "" Then strOutput = objResult.Output.Item(x)
         Else strOutput = strOutput:@LF:objResult.Output.Item(x)
      Next
   EndIf
   ; Compiler Errors
   If objResult.Errors.Count > 0
      strErrors = ""
      ForEach ce In objResult.Errors
         If strErrors == "" Then strErrors = ce.ToString()
         Else strErrors = strErrors:@LF:ce.ToString()
       Next
      strOutput := @lf:@lf:"Compiler Errors: ":@lf:strErrors
      bError = 1
   EndIf
   if strOutput != ""
      Pause('Compile Report', strOutput)
      if bError then exit ; Abort on compiler error.
   endif
 
   ; Releasing objects is not necessary because all valiables
   ; are automaticaly release because the UDFs variable table
   ; is cleared when the variables go out of scope.
   return 1
#endfunction

ObjectClrOption("useany", "System")

;; In Memory compilation.
CompileWbNameSpace()

; Get an instance of our newly compiled list.
objWbList = ObjectClrNew("WinBatch.PartsList")

; Add a part to the list.
Part = ObjectClrNew("WinBatch.Part")
Part.PartName = "Widget"
Part.PartId   = 1
objWbList.Add(Part)
x = objWbList.Count()

Pause("Lame Example", "Hopefully x is one: ":x)



It would appear the latest forum software upgrade is causing the forum's syntax colorizer to turn single quotes into their HTML equivalents. Double quotes seem to be unmolested, however.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Quote from: ChuckC on March 28, 2022, 12:48:58 PM
PowerShell isn't required, per-se, to perform dynamic compilation of C# code, so your constraint of not utilizing PowerShell shouldn't be a factor.  PowerShell does, however, make it easier to create an instance of a generic container bound to specific key/value types without dynamic compilation of C# code.


I meant just writing code in PS and shelling it from WB with addcode(). Tony's hack is going to come in handy for a special case.

td

The above example could be streamlined to avoid having to write covers for all the List object's methods and properties. For example, it is simpler to just do the following:

Code (winbatch) Select
; Add a part to the list.
Part = ObjectClrNew("WinBatch.Part")
Part.PartName = "Widget"
Part.PartId   = 1
objList = objWbList.GetPartsList()
objList.Add(Part)
x = objList.Count()

Pause("Lame Example", "Hopefully x is one: ":x)
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Quote from: td on March 30, 2022, 07:39:12 AM
The above example could be streamlined to avoid having to write covers for all the List object's methods and properties. For example, it is simpler to just do the following:



same code as in original. What makes it simpler?

ChuckC

It's subtly different... Look closer...

stanl