Interesting question came up while designing interfaces at work, now resolved, but I want to ask about the theory behind it.Is it incorrect to say that properly typed data members of a class provide encapsulation? (e.g. a Boost Units type that has conversions well defined between other like units, not a typedef'd/boxed uint64_t)struct Ruler{    Length length;    Length tick_size;       Ruler(Length length, Length tick_size);    // Why not have helpers immediately related to the class, let's    // stick in an alternative constructor    Ruler(Length length, int number_ticks);     // Accessors for # tick marks, because it needs transformed     // to/from length and tick_size    int GetNumberTicks(void);     // This specific example breaks down with this function,     // but I don't think it's an inherent issue with the design.    // I need an overload so it will know which of the two member     // variables to calculate... problem is both are Length    void SetNumberTicks(int nticks); }vsstruct Ruler{            Ruler(Length length, Length tick_size);    Ruler(Length length, int number_ticks);     // General accessors    Length GetLength(void);    void SetLength(Length length);    Length GetTickSize(void);    void SetTickSize(Length length);    // Calculated accessors, see above    int GetNumberTicks(void);     void SetNumberTicks(int nticks); private:    Length length;    Length tick_size;   }IMO the first encourages cleaner design by consumers and doesn't encourage pulling in slightly related, but probably attached to the wrong object member functions (eg CanMachineCreateRuler() ). I don't really have the words to describe this properly and I may be misunderstanding the additional utility that the accessors/private data combination provide.
Can encapsulation be implemented by proper types rather than accessors?
c++;object oriented design;solid
Accessors for basic data types generally come from the additional operators available to those types.   While getting and setting variables may be allowed, keeping extra references to those variables is often discouraged.Some languages also need accessors when the encapsulated program wants to make changes at the time an accessor is used, e.g., computing a lazy value or invalidating a cache.Much of this can be solved by creating general accessor types, such as an int, that has been initialized, for which no address can be obtained, which is not a NaN, is signed, and, upon overflow takes the largest absolute value allowed. or an int, that has been initialized, which is arbitrary meaning no arithmetic operations are allowed, for which references can be taken.   The choice is often to trade off the pain of specialized types versus the pain of dependency injection.