Can you expand a bit please ASF?
It's been pretty well covered above, but yep - it's mostly just that AOP's can have meaningful data structures instead of just an array of SINT's.
Of course, a good GEM implementation will still wipe the floor with a bad AOP implementation - just having an AOP doesn't guarantee that it's inherently better than using the GEM option - only that it has the potential to be.
Best case scenario on GEM: your instance numbers, data types and data structures are all well documented and easy to find. You set up your GEM, add in all of that data manually, write some code to map the data into meaningful tags, and you're done. Relatively painless.
Best case scenario on AOP: your AOP is well constructed with meaningful tag names and is easy to find/download/install (some devices actually have the AOP available
on the device itself downloadable from a web browser). It's also well documented, but that hardly matters because you just install the AOP and drop it in, and you don't even need to map anything, you just start programming.
Worst case scenario on GEM: your instance numbers, data types and data structures are poorly documented, documented incorrectly, have been changed since the manual you have was written with a firmware update, or are simply not published anywhere you can find. You spend a lot of time hassling distributors and/or tech support trying to get the information you need. Eventually you get it communicating and then have to do some playing around to work out how the different commands and statuses interact. Then you write some code to map the data into meaningful tags. Hugely painful, and yes, I've had devices like this. One device in particular had 7-8 different manuals, and none of them contained the instance data. Tech support couldn't find it anywhere, eventually they fired up one of the developer's laptops and took down his settings from a test rig. It must have taken me 40-50 emails back and forth with tech support to nail down the complete functionality of all of the data.
Worst case scenario with an AOP: the AOP just gives you an array of DINT's, vaguely named with things like "StatusWord" and "CommandWord" and very poor documentation as to which bits in each word do what. You're in a similar position to where you were in the GEM worst case scenario, except at least you don't have the added complication of having to find non-documented instance numbers.
TL;DR - a well-documented, well-supported GEM implementation will beat a poorly-developed, poorly-documented AOP. But a good AOP beats a good GEM, and a bad AOP still beats a bad GEM