3 ms·
Then maybe you should have manager's IDs done as separate type too?
by mic47 8y ago
Then maybe you should have manager's IDs done as separate type too?
- osrec 8y agoBut they're all users, where one user can be set as a manager for another. Why would you have a separate type for each?!
- tom_ 8y agoBut your example implies you shouldn't be allowed to get them mixed up? If manager IDs and user IDs truly are the same type of thing, then there's a limited amount the type system can do for you in this respect. Maybe you'll have to stop at this point and just accept that you'll have to exercise a certain degree of care. But there's a big gap between stopping there, in my view, and what you appear to be advocating: deciding that since manager IDs and user IDs are the same thing then you might as well give up entirely and just decide that they may as well be the same thing as ints while you're at it.
- osrec 8y agoNot quite. If I was to truly critique the example, the problem lies mainly with the ban function, which appears to allow ints to be passed in as arguments. If we have static typing available to us (the example in the article doesn't seem to), then yes, I agree we should ensure that only the relevant type should be allowed as the argument. But still, problems can lurk in the shadows, for example, you could initialise a User type with a message ID by mistake, or even an iterating int, much like the example in the article. I'm not trying to be difficult or unnecessarily contrarian, but my experience tells me that you can put a whole bunch of safeguards into your code, but nothing beats testing at catching bugs, and sometimes, the safeguards are not worth the efficiency hit. Worse still, the safeguards can at times provide a false sense of security.
- tom_ 8y agoIt shouldn't be an excuse to dispense with testing altogether, but static typing is certainly superior to testing for certain classes of bug. The compile-time checks prove certain types of defect simply don't exist, which is the kind of guarantee no amount of testing can give you in that respect for any useful program. As for the initialisation problem, it's true that it can't be structs all the way down, and at some point you will have to create one of these objects, probably from a primitive with a non-meaningful type such as int, or string. But my experience is that IDs and the like tend to be created in a small number of places, and then reused, copied and passed around. Far easier to find and check all the places where one is created than all the places where one is used!
- mic47 8y agoIf you need to mix them up, there is bunch of options. It all depends on what you need to do, and what language you are using, but usually there should be simple solution to this. For example, if you simply want to have functions that works for both of them (so that you don't duplicate code), you can either create function from Manager to User (so that you can reuse functions for users), or use whatever polymorphism stuff your language support (polymorphic function, OOP, ...). If you want to mix User/Manager in same collection (or have function that returns any of those), OOP can help too (Manager is "child" of User). If your language have sum types, you can use those (have additional type "User or Manager", and accompanying matching/extraction function). In some languages you can do this with no runtime overhead (i.e. the additional type will be erased during runtime, as it's already type checked).