Purpose of Object[]

Hi guys can anyone let me know why do we use Object and what it the purpose of it. How to search in the browser for more…I have seen usually we use in datatable etc…

1 Like

Hi,

If you want to store array of objects you will use object and you can browse as Array of [T] and select the type as object.

Suppose you have a application and it has a table and values will be stored in an application as object, while getting the values that’s why we convert from object to string or to other types like datetime.

2 Likes

Hi @balkishan

Array is used to store the same type of variables.
For example int can store only array of integers.

To store different types of variables we can use object array.
object can store any type say integer, boolean, another array etc.,

But it requires boxing and unboxing where computation is high.

Boxing -> converting type (int) to Object
Unboxing -> Converting Object to type (int)

Hope you are clear now.

Regards,
Karthik Byggari

4 Likes

@KarthikByggari @anil5 Thanks so much guys!! :slight_smile:

1 Like

It may seem like nitpicking (and probably is), but to avoid some misconceptions spreading I will.
Don’t take it personally, a lot of the times these things don’t matter, but if you start mixing terms it will be harder to learn and use properly more advanced concepts.

This is true, but should be avoided whenever possible.
An array by definition is a collection of homogenous objects (that is objects that share the same type). While in .Net technically everything is an object, storing completely different things in the same array will lead to bugs (and possibly a head-smack from someone who needed to debug it).
An Object[] in today’s day and age pretty much doesn’t have a usage outside of really fringe edge-cases and specialized scenarios.
It is also, especially in UiPath context, pretty much a useless way of storing things, because the only thing you could do while iterating over it is element.ToString(), but you don’t know what it will return - depending on what object type is there actually, it may return 7 or 5/2/2018 12:24 PM or (as an extreme example)

"System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

You still have to put it in an object that it is actually of to do anything meaningful with it.

Not in UiPath context. If you’re worried about (un)boxing costs, you’re using wrong technology. An Assign activity (source here) is more computationally intensive than boxing and much more at that.
Also - all variables are actually boxed, even if they’re a value type (like integer), so in reality boxing is probably one of the last things you should worry about in your project (or in reality - shouldn’t even make the list of things to worry about).

Note - (un)boxing only happens for value types, so depending on what you have it may or may not happen. For int it would happen, but for an int[] it will not (since it’s a reference type).
Secondly, and what lead me to write this in the first place, (un)boxing does not convert. It does a direct cast.
There is a subtle, but important difference - direct casting will fail if the casted object is not the target type or a subtype of it, because it just reads the memory straight as-is (it’s like pointing a different type of a pointer to the same memory address).
So for example converting an int to decimal will work without any problems, but direct casting will not (conversion cast will work, though). Even casting from int32 to int64 (which is well suited for having any value that an int32 can throw at it) will fail, because the types don’t match.

Again, these things will probably never matter to whatever you do in UiPath and the takeaway should be just “don’t use System.Object unless you really really have to (pretty much never), use more specific types (pretty much always)”.

3 Likes

In the past, I have used System.Object[] as an argument, as a way to allow the ability to send either numbers or strings, depending on the project.

Like let’s say you have an array of columns as an argument, but you don’t know if they will be column indexes or column names. So in order to allow for flexibility, you give it the ability to be either type. Then, in your code you check the type of the object and parse it accordingly. For example, col = If(IsNumeric(obj), Convert.ToInt32(obj), obj.ToString)

So, what is your opinion on this use case? It’s really the only time I have considered it, when I want the workflow to work for multiple types, but also check the type before using it. Or maybe there’s another method that would work better, but like in my opinion it’s similar to a Dictionary, JArray, or DataRow items in that the items are objects and require the same kind of logic to check the type and convert it. — I’m always trying to learn more. Thanks.

2 Likes

Well, if you mean declaring a variable of this type, maybe we can consider it a edgy.
However this existense of the concept itself is crucial in .Net and UiPath (Existense of array or other Enumerable(of Object) to have a return Type for entities such as Datarow and use Linq on it.

It is also use quite often when it comes to ItemArray property of a Datarow (to add or overwrite its content) even if it is done often like row.ItemArray = {var1,Now.AddDays(-1), dtItems.rows.count}

It is rare enough that I disagree with you to emphasize it, this time I do! :slight_smile:

Cheers

1 Like

I’ll try to keep it specific to UiPath context, so please forgive any omissions that would be relevant outside of it. If any parts of the post seem aggressive, please note that it’s not an aggression towards people asking, but frustration that one of the most used types in UiPath (DataTables) is based on object notation and thus it’s pretty much the only reason we’re having this conversation (which is interesting in itself, but still).

The fact that it’s heavily used (or in reality - needs to be used) with DataTables shows exactly the problem I have with both.
An object[], while useful for the computer, doesn’t help the programmer (especially the poor maintenance guy) because it is not strongly typed in an environment that is strongly typed (UiPath is not only .Net based, but specifically VB.Net needs to be used with Option Strict On, so you cannot assign a value to a type that doesn’t accept it).
I’m not going to argue against using it when you need to, but I will try to find pretty much any other way if I’m declaring a variable explicitly, even if it means more code, specifically because for me #TypesMatter. And they do also for the “future me” that is going to try to recreate a situation where somewhere along the lines an unexpected thing will be stored in one of those Objects in a DataTable and backfire on iteration 7852.

We’re currently using a lot of (relatively a lot of, at least) object[] because DataTables are one of the central themes in UiPath. They’re useful, no doubt about it, but they lack strong typing (technically that could be worked around to create strongly typed DataTables, but it’s a pain to do so and would probably not be worth it).
One needs to keep in mind, that DataTables were a part of .Net before Generics were added (generics -> C#2, datatables -> C#1.1) and the same as everything that was there at the time, rely on specialized, non-generic types. Due to the need of backwards compatibility they couldn’t rework or remove the non-genericity of them and now, 16 years later, we’re still using object[] for ItemArray, and DataRowCollection (instead of ICollection<DataRow>) etc.
DataTables, just like object[] are relics of the past (for the former at least the implementation is) and while still useful, they have had their original, unchangeable right now, design built not only on special-case classes, but also for a different audience.
Even the creators of C# admit (I’ll find the links if needed), that the language itself shouldn’t have been released before generics were ready, but they needed to respond to Java (note that v1 of C# was the only to have minor versions for 14 years - it was released unfinished due to market pressure).
Did you ever wonder why anything related to IEnumerable was added to DataTables as extension methods (including in separate assemblies)?
Or why were the extenstion methods for Field<T>(DataRow, [columnIdentifier]) added just to specifically cover the missing feature of having strongly typed access to row fields (and you still need to know what T to pass as again, no validation check before runtime is possible)?

Or why below code even compiles?
image
It’s so obviously wrong and current tools are so sophisticated in catching coding errors that it’s amazing that this is, from compiler perspective, legal code. It’s of course going to blow up during execution, but until that point nothing will warn you of anything.
Now imagine that situation in UiPath context, where the assign happens 4 invokes later. Do you want to check how the DataColumn was declared, because I surely don’t.

To just sum it up quickly here:
Usage of object[] should IMHO be avoided whenever possible for the simple fact that it circumvents one of the key defining characteristics of .Net in general - .Net languages are strongly typed. Object technically is a strong type, but in practice is almost like a pointer.

Continuing to a more direct response:

ItemArray is actually a pretty interesting case.
Due to how DataTables work, it needs to work on object[], but I’d be hard pressed to find anyone who actually likes how it works. It’s extremely easy to make a mistake with it in various different ways.
DataTables in general are one of the few types that come to mind (or actually - the only one I can think of right now, but there are probably a couple more) that are so easy to break in seemingly unrelated places. Added/removed/shuffled/renamed a column? Better check your whole project to find all places where it breaks and no, there will be no compiler errors anywhere.

Even the way you wrote the the ItemArray example - while correct - as a maintenance programmer (just wear the hat for a second :wink: ), can you tell me what type should var1 be for the rest of the solution to work? Or even this specific line to work?

In reality, you have to know, at all times, the schema of all your used DataTables, to be able to use them. With anything that is actually built upon generics, if you have a reference to an object (not object as a type, but an object as in instantiated class) you know what it contains. If I pass you an List<Employee> object, you can get first element, write employee. and see exactly what it has - that FirstName is a string, Age is a double etc. If you try to pass something else, you’ll get a validation error.
If I pass you a DataRow, you’ll have to hunt the project files to find the declaration of it, hope you found the right one, hope it’s not changed anywhere along the way (add/remove/rename column), and hope it’s not ReadRange(Range = ""), because then you have to find the file it reads, check what columns it has and check documentation for what values might be there (you probably encountered the wonderful feeling of iterating over a datatable and seeing “Date, Date, Date, DbNull, String” in a column).
That’s only because someone somewhere decided that “let’s read the excel as a 2-d array of objects equivalent” was a good idea (IMHO - it wasn’t a good idea, but probably a compromise between having something useable for non-programmers vs something that would require pre-building the DT/structure).

The Enumerable(Of Object), unless you meant the non-generic Enumerable, is actually a Enumerable(Of T), so Object is just one type that it can work on. Since you mentioned LINQ, I’d guess you probably meant the generic version, so no, it has nothing to do with using (as a programmer, not as the computer) the type Object directly.

So to really summarize this part of the response (and again, this is fully IMHO):
object[] as an explicitly used type is an archaic concept and should be avoided whenever possible, replaced with generic collections.
If something uses object[] and I have to use it, that something is going to have as short of a lifetime in my project as I can get away with and disposed of immediately after (btw - DataTables linger in memory because they require finalization, not only disposing, another reason why they should be avoided), because as a responsible programmer, I need to know what datatypes I’m actually working with to not introduce silent data corruption in the systems I’m automating, or “random” crashes, and using object as a type it does not allow me to do that.

@ClaytonM
This use case is interesting.
I’d still avoid accepting an object[] though, because otherwise this is a valid invoke:

{ Columns = {0, 1, 5, "Thursday", "RealColumnName", myDt.Columns(5), 81.4, aSecureStringVariable }

Yes, someone would need to be crazy to do that (although with the code part you’ve showed everything up to 81.4 would work as expected), but the fact is - you as the component creator allow that.
An argument should signify what is allowed and how it will be used not only by its name, but also type. That’s a sign of a good API, that you literally don’t need to know anything about the internals of something, and you can still use it normally.

A lot depends on how your workflow signature looks like (name + arguments) and what you’re aiming for, but I’d probably implement it in one of 2 ways:

  1. Have 2 arguments, one IEnumerable<int> ColumnIndexes and second one IEnumerable<string> ColumnNames. Passing both would either be legal (if it’s expected use) or throw an exception, but in any case the type safety would be guaranteed. From what you described, it’s an either/or relationship, so probably throw on passing both. Internally, the workflow would use indexes (probably), so if you pass strings I’d map it. Or it would fetch DataColumn objects and I’d map both with a Try pattern.
  2. Implement a custom activity that does whatever needs to be done to that DataTable and use an OverloadGroupAttribute to make sure only one of those can be used. In this route, I’d probably add a third option for an IEnumerable<DataColumn> (if you’re aiming for flexibility for the caller).

In any case, for components like this, I’d still avoid allowing object[], simply because I’d either need to validate all of them beforehand for eligibility and cross-mapping or risk it breaking on the n-th column. Due to DataTables and argument reference copying working like it does, this would mean that the n-1 columns have or potentially have already been altered and thus my data just lost integrity because I’ve processed a portion of a row and my data is already altered in that portion.

By allowing only known types, I know that the call myDt.Columns(passedElement) will be a valid call. It might throw due to mismatch like index out of range or misspelled name somewhere (and it would be wise to pre-check index and column name mappings anyway - f.e. try to map both ints and/ro string to a local collection DataColumn and operate on that due to knowing that it is safe from column mapping perspective), but at the very least I know what I have to work with.
If I accept object I have literally no idea what I’m processing.

Sidenote:
IsNumeric is interesting, but I’d avoid it for checks like this - an index has to be an int, check if it’s an int not just any number. Or actually - if it’s a non-negative int.

If it works for you, it works for you.
If someone would do that in a single project? Would get a talk about it (and flexibility most likely wouldn’t be a needed thing anyway).
If someone would propose to do that as a reusable component? I’d probably go the “nope” route. A reusable component has to have a clear and unambigious usage that makes it hard to misuse. Accepting an object[], which could have literally anything (up to and including function invokes) is a no-fly zone.

Side question:
Out of curiosity, what did that component do? I’m struggling to find a suitable usage for such a construct, but it might be because of the object[] frustration :wink:

Also a general side question:
If object[] is ok and also DataTables are ok, why is ORM a thing?

3 Likes

Took me a while to figure out where I used it! This particular component is used to take a data row in a table and update certain columns, and also shade certain columns if desired; it also removes the duplicated row if it had been processed before already. It was being built as an UiPath solution to eliminate any need to think about how to update tables during a process like status messages or anything else, which is needed for basically every project.

Here are two example arguments:
in_UpdateColumns <of Object[]> = {"Status"}
in_UpdateValues <of String[]> = {"Complete"}
So it would put the value in the corresponding column. It is also unsure that the table will have column headers or not, so index would need to be a viable option.

I wonder if it would be better to use DataColumn[] as the type instead so the caller can decide to use index or name as they choose.

I found another instance where I created a project-specific setting to store an index and string in the same array. As it’s not really a shared setting, I’m not going to get too concerned about that one.

And, yeah, I agree that Objects open up potential that you are unknowingly sending a type that is wrong. But I suppose in the internal departments of a company, it’s not a big deal.

Thanks for you input.

2 Likes

If think if there is something we can agree on, it is that this topic (tagged as Rookie) has gone miles away from the UiPath context.

I am not saying this is wrong, UiPath is still closely related to .Net and its concepts and this is why I (and I think many) prefer it over other RPA tools in the market.

That’s all good :slight_smile: We are on a Forum discussing ideas and concepts, we understand that it isn’t personal (AFAIK Datatables aren’t persons :D). but overall things are starting to make sense, your inherent hate for Datatable, the Custom activity entity etc…)

Yes, I think you won’t struggle finding out people agreeing with you on that one, I would even say the vast majority of Dev community will agree you on that (the UiPath one but also the .Net one).
Being one of the last coder preferring VB.Net over C#,I have my personal reasons, the option strict off being one of them. That doesn’t mean the I think you should not declare your types for showing your intent when you code, but having the possibility to not have to do it can come to be handy. #TypesDontAlwaysMatter

I think you, .Net devs and your Haunt of having the wrong type and the wrong has always been fascinating, If this was something legitimate to worry about in C, Assembler or other remains of the past. Are also finding useless the concept on indices (being plural of index) because they can throw an Index of out range exception.

That’s right, they (DTs) are useful mainly because when you deal with a spreadsheet you effectively may have no idea what it may contain and you will still to have a type which will permit you to access/browse it programmatically. Json could have been used but I am not sure I would be enjoy spreading to a wide audience what is a Linq Functor above that how a dt.Select works :slight_smile:

UiPath is built upon .Net but also old technologies such as Interops, using heavily com object so you need something large enough to handle this tech range.

Once again, blow up a is a little exaggerated way to call a type mismatch exception :smiley: but I got your point!

Those are good points, it is one of the drawback, on the other hand coming back of the spreadsheet to UiPath issue, you would heavily struggle to make the conversion between a spreadsheet to a class/entity.

Well, Object (C# synthax or Object() {} in Vb.Net) which I believe was the topic is an IEnumerable (Generic) already and I on the contrary say that it has something to do with the using the Type object directly but maybe by using, you mean having a variable of this type?

I may have got wrong your idea but my understanding is that you defend that the Concept of Object itself accessible to the developer is obsolete in .Net, this is what I disagree with :slight_smile:

100% agreed, however “Avoid wherever possible” implies that there are places it will be necessary to use it.

Cheers

4 Likes

You might want to look into dynamic usage. It’s basically an equivalent of Option Strict Off.
Personally I’m not a big fan (probably no surprise there :wink: ) as it changes compile-time errors to runtime errors, but it has it’s uses. I’d like to note that dynamic and object are different beasts, though - one uses “compiler magic” to make things work, the other requires specific handling by the programmer.

Well, we’re operating in a strongly-typed environment, so that’s natural. It’s more of an OOP thing and you’d probably find similar, or stronger, opinions in other OOP languages.
And I wouldn’t necessarily agree that it’s a thing of the past - current OOP languages will error out in a similar way (although a less drastic one than a memory access violation).

It’s interesting you brought up Interop, because it actually shows the issue I have with passing object types around very well - even though from a technical perspective you need to pass an object, that object has to have very specific content (including fields declared in correct order), because it will be read on a level low enough that having incorrect structure can make it execute in unpredictable ways (if you get a cryptic error from that it’s still better than it misinterpreting the bits and bytes that were sent).
That’s why a lot of the times when dealing with COM there are special classes specifically built to make sure the data is sent in a correct way (i.e. strongly-typed structures).

Well, I might’ve worded it wrong then.
Objects are the fundament of OOP. Having it accessible is necessary and there are scenarios which would not be possible without using it (i.e. reflection).
But due to how OOP functions, there is very rarely a reason to directly use object as a type for “a concrete thing” because it’s by definition not concrete.

In the end I think we’ll need to agree to disagree on this.
I’m happy anyway that we agree that they shouldn’t be used willy-nilly.

Cheers :slight_smile:

4 Likes

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.