I have read that sometimes, using "bulk" operations can be good for performance, and execution time
What Billy means is that you shouldn't believe everything you read, or in some cases you should investigate further to better understand what is meant.
Yes, Bulk operations can be fast.... when you compare them to row by row processing in a loop.
But Bulk operations will not be faster than a single SQL statement.
In terms of performance, you should always aim to do it just in SQL first, and then if that's not possible, look at doing bulk operations (though those occasions should be rare!)
But is it possible using "forall" and bulk insert (forall applied on that "object" type)?
Yes - it is possible: Just use 'forall applied on that "object" type':
l_dt TListProdTab:= TListProdTab();
for i in 1..10 loop
l_dt(l_dt.last) := TListProd(i);
forall i in l_dt.first..l_dt.last
insert into test123 values('Something', l_dt(i).product_id);
Can we assume that your example is just an 'example' of you trying to learn some concepts regarding collections? Because that 'example' doesn't need collections or object types at all to just insert a string constant and a row number.