%%% basic version

classdef VUPair < handle
    properties(SetAccess = private) 
        value = 0;
        uncertainty = 0;
    end
    methods
        function obj = VUPair(val, unc)
            if nargin > 0
                obj.setValue(val);
                if nargin > 1
                    obj.setUncertainty(unc);
                end
            end
        end
        function setValue(obj, value)
            if numel(value) ~= 1 || ~isnumeric(value)
                error('Value must be scalar.')
            end
            obj.value = value;
        end
        function setUncertainty(obj, uncertainty)
            if numel(uncertainty) ~= 1 || ~isnumeric(uncertainty)
                error('Uncertainty must be scalar.')
            end
            obj.uncertainty = abs(uncertainty);
        end
        function disp(obj)
            if numel(obj) == 1
                fprintf('   %g %s %g\n\n', obj.value, char(177), obj.uncertainty)
            else
                fprintf('   %dx%d VUPair\n\n', size(obj,1), size(obj,2))
            end
        end
        function out = plus(obj,obj2)
            if isnumeric(obj2)
                out = VUPair(obj.value+obj2, obj.uncertainty);
            elseif isnumeric(obj)
                out = VUPair(obj2.value+obj, obj2.uncertainty);
            elseif isa(obj, 'VUPair') && isa(obj2, 'VUPair')
                out = VUPair(obj.value+obj2.value, sqrt(obj.uncertainty.^2+obj2.uncertainty.^2));
            else
                error('Cannot add %s to %s.', class(obj), class(obj2))
            end
        end
        function plot(obj)
            errorbar([obj(:).value],[obj(:).uncertainty])
        end
    end
end


%%% version with some bells and whistles

% classdef VUPair < handle
%     properties(SetAccess = private) 
%         value = 0;
%         uncertainty = 0;
%     end
%     methods
%         function obj = VUPair(val, unc)
%             if nargin > 0
%                 obj.setValue(val);
%                 if nargin > 1
%                     obj.setUncertainty(unc);
%                 end
%             end
%         end
%         function setValue(obj, value)
%             if numel(value) ~= 1 || ~isnumeric(value)
%                 error('Value must be scalar.')
%             end
%             obj.value = value;
%         end
%         function setUncertainty(obj, uncertainty)
%             if numel(uncertainty) ~= 1 || ~isnumeric(uncertainty)
%                 error('Uncertainty must be scalar.')
%             end
%             obj.uncertainty = abs(uncertainty);
%         end
%         function out = toVector(obj)
%             out = [obj.value obj.uncertainty];
%         end
%         function disp(obj)
%             if numel(obj) == 1
%                 fprintf('   %g %s %g\n\n', obj.value, char(177), obj.uncertainty)
%             else
%                 fprintf('   %dx%d VUPair\n\n', size(obj,1), size(obj,2))
%             end
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         function out = plus(obj,obj2)
%             if numel(obj) > 1 || numel(obj2) > 1
%                 if numel(obj) == 1 || numel(obj2) == 1 || isequal(size(obj), size(obj2))
%                     outsize = max(size(obj), size(obj2));
%                     out(outsize(1),outsize(2)) = VUPair; % this requires the constructor to accept 0 input arguments
%                     if numel(obj) == 1
%                         for k1 = 1:outsize(1)
%                             for k2 = 1:outsize(2)
%                                 out(k1,k2) = VUPair.scalarplus(obj,obj2(k1,k2));
%                             end
%                         end
%                     elseif numel(obj2) == 1
%                         for k1 = 1:outsize(1)
%                             for k2 = 1:outsize(2)
%                                 out(k1,k2) = VUPair.scalarplus(obj(k1,k2),obj2);
%                             end
%                         end
%                     else
%                         for k1 = 1:outsize(1)
%                             for k2 = 1:outsize(2)
%                                 out(k1,k2) = VUPair.scalarplus(obj(k1,k2),obj2(k1,k2));
%                             end
%                         end
%                     end
%                 else
%                     error('Dimensions must agree.')
%                 end
%             else
%                 out = VUPair.scalarplus(obj,obj2);
%             end
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         function out = uminus(obj)
%             out = VUPair(-obj.value, obj.uncertainty);
%         end
%         function out = minus(obj,obj2)
%             if isnumeric(obj)
%                 out = VUPair(obj-obj2.value, obj2.uncertainty);
%             else
%                 try
%                     out = obj.plus(-obj2);
%                 catch myerr
%                     error('Cannot subtract %s from %s.', class(obj2), class(obj))
%                 end
%             end
%         end
%         function plot(obj)
%             errorbar([obj(:).value],[obj(:).uncertainty])
%         end
%     end
%     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     methods (Hidden = true, Static = true)
%         function out = scalarplus(obj,obj2)
%             if isnumeric(obj2)
%                 out = VUPair(obj.value+obj2, obj.uncertainty);
%             elseif isnumeric(obj)
%                 out = VUPair(obj2.value+obj, obj2.uncertainty);
%             elseif isa(obj, 'VUPair') && isa(obj2, 'VUPair')
%                 out = VUPair(obj.value+obj2.value, sqrt(obj.uncertainty.^2+obj2.uncertainty.^2));
%             else
%                 error('Cannot add %s to %s.', class(obj), class(obj2))
%             end
%         end
%     end
%     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% end

