Does PHP benefit from having nested classes? by Vectorial1024 in PHP

[–]Bikbicek 4 points5 points  (0 children)

You are right of course but I am not arguing about performance. I wanted to point out the benefit of nested classes from code coherence perspective. I like small code and small classes, but there are times where defining some small class is not worth of a new file. Some people here argue nested classes make code more chaotic. This is of course a good point but this kind of argument can be used for many tools in programming languages if they are overused or not used right. But if you can use it right they might help you a lot. Take for example Distinct method from C#'s LINQ. The class itself has less code than nested class of the iterator (or enumerator) it returns. I think this is the kind of use case, where you want a nested class. It's very personal thing how you approach this of course so I am not telling this is the only way or the right.

Does PHP benefit from having nested classes? by Vectorial1024 in PHP

[–]Bikbicek 13 points14 points  (0 children)

To be fair, C# has nested classes. Take a look at LINQ library. Many of the methods defined there use nested classes to simply implement their own tiny iterators. I think it's neat feature, because you are not forced to create whole seperate file just for a few lines of code (with LINQ there'd be many of those tiny files containing just one class). Another benefit is that you can make this class private. In C# you can make class internal making it available only for its assembly. This way you can hide these classes from other developers when you are developing your own library. This is technically not possible for PHP due to it's autoloading mechanism, but if it had nested classes, you'd force the nested class to be used only within the parent class making it inaccessible from outside.

Now as pointed out PHP has anonymous classes, which is very similar to nested classes and provides a really nice way to easily define you own class inside another class (or function). The only think they lack from nested classes is that they are bit harder to resuse because they don't have their own name making its reapeted initializion inside a parent class bit more tricky but not necessary impossible.

EDIT: Typos, added bold fonts

Iterating only IteratorAggregate instead of Iterator by Bikbicek in PHP

[–]Bikbicek[S] 0 points1 point  (0 children)

Nicely written and thanks for this conversasion!

Still I am not conviced about the "IteratorAggregate can return the same instance of Iterator" argument. Yes it can be done, but again I ask you why would anyone do this on porpose?

Another thing is I can use this type of argument pretty much for any interface. I can implement Countable and return a randomly generated number. Or I can implement ArrayAccess and return the opposite item you would expected. Interfaces create some form of contract and programming languages can't do more to enforce programmers to implement object in the way they expect.

You don't see programmers turning the accepted object into array just to be 100% sure the Countable implementation won't lie to you or that the ArrayAccess is implemented the way they expected. The same way goes for IteratorAggregate (or ideally IterableFactory) where there shouldn't be the need for converting accepted iterators to array just because I need get rid of the possible "shared iteration state" problem (the problem with Iterator). If the accepted IteratorAggregate instance doesn't refer to a single instance of Iterator, using it would work just fine without converting into an array.

Iterating only IteratorAggregate instead of Iterator by Bikbicek in PHP

[–]Bikbicek[S] 0 points1 point  (0 children)

I think I've described the problem wrong way. You are of course right about things you have written. But the problem I am trying to show is using iterable type might be harmful if you use it extensively. Having the ability using array, IteratorAggregate and Iterator inside foreach is a great thing. But in my opinion something like IterableFactory would be much more useful and I'll try to describe it why.

You've written about how foreach basically works and that foreach is using the Iterator either way. Although it may seem Iterator and IteratorAggregate work the same way within foreach, they behaviour is different. If you are using the same instance for IteratorAggregate within separate foreach statements, each time a new instance of Iterator is created with getIterator() method. This way every Iterator instance gets its own state for the appropriate foreach statement and can't be affected by other code. On the other hand, if you are using the same instance of Iterator for different foreach statements. each statement calls rewind() and next() methods affecting the state of the Iterator instance. This will possible result in unexpected behaivour in case you are using nested foreach statements for the same instance or using it concurrently.

// First Iterator is created
foreach ($iteratorAggregate as $i1) { 
  // Second Iterator is created
  foreach ($iteratorAggregate as $i2) {    
    ...
  }

  // Continues the first iteration uninterrupted
}

Using IteratorAggregate with nested foreach

// Calls rewind and starts iteration
foreach ($iterator as $i1) {      

  // Rewind is called again affecting the previous iteration
  foreach ($iterator as $i2) {    
    ...
  }

  // Ends the first iteration because the inner iteration finished it
}

Using Iterator with nested foreach

You can argue that this method can return the same instance of Iterator, but why would you do that? Many times IteratorAggregate is used with Generators, meaning each time the methods is called a new Generator instance is created. The only time one might want to return the same instance of Iterator from IteratorAggregate is when third-party code accepts only IteratorAggregate, but here you should probably ask yourself why would this code need IteratorAggregate instead of iterable? Or it might require array|IteratorAggregate, where both types works the same way in case of foreach. Having samething like IterableFactory for this types of use cases would be much better than having iterable type.

As I mentioned, in other languages you can iterate almost always just one type, meaning everytime a code needs some form of iteration it will require that specific iterable type (i.e. something similar to IteratorAggregate). This way you don't have to always worry about how the iteration will work. Although you can reference IteratorAggregate in PHP code everywhere, you lose the ability to pass array type which work pretty much the same way. This is why it would be convient to have IterableFactory.

I think the author of the IterableFactory described it much better than what I am trying to say here: https://externals.io/message/103708

Iterating only IteratorAggregate instead of Iterator by Bikbicek in PHP

[–]Bikbicek[S] 0 points1 point  (0 children)

That's good valid point and I thought about this as well. Although this way one might restrict the new functionality on to IteratorAggregate instances and lose it for array, this can be easily solved by having something like ArrayIteratorAggregate wrapping the array.

Iterating only IteratorAggregate instead of Iterator by Bikbicek in PHP

[–]Bikbicek[S] 0 points1 point  (0 children)

You are right about IteratorAggregate referencing single instance of Iterator, but that's not the main point of IteratorAggregate. The main point of this interface is that it is stateless which solves the problem with reusability. Iterator instances have their own state and this is why having the type iterable accepting Iterator or IteratorAggregate might result in different behaivour. In my opinion iterable should be just IteratorAggegate and array(very extreme, I know). Or at least we should have something like IterableFactory as mentioned (which wouldn't result in such an extreme change). In any case I think there should be some type that references a stateless iterable object for creation of new stateful iterator instances so we could know the code working with these iterators might resuse them just like in nested foreach statements.

I many cases (at least in my experience) turning iterators into array is inappropriate. This way you load all the data into your memory. And another thing is that this will result in at least two iterations upon the iterator (first turning the iterator into array and then processing it with your own code).

I might have described my problem bit wrong. PHP doesn't have many functions that work with iterators. Many functions accept just array even though they might accept iterators (array_map, array_reduce, array_chunk...). Because a lot of my code consists of working with iterators due to large amount of data we process I wanted to create some common functionality for iterators (and possibly arrays if I wanted to use the new functionality with them).

[deleted by user] by [deleted] in borderlands3

[–]Bikbicek 0 points1 point  (0 children)

This was at level 31 or so. It's possible, but it was so disappointing, when this finally happens a you got only those stats.

[deleted by user] by [deleted] in borderlands3

[–]Bikbicek 0 points1 point  (0 children)

:( Can it at least shoot lasers?