Advantages and drawbacks of different ways using Either-types [closed]

I am writing software for compiling programs. Therefore have a Compiler that compiles a given sourcecode. It then returns a CompileResult that is similiar to an Either type (it is actually internally delegating to an Either object). Now there can be 2 (non-exceptional) cases:

  1. The compile is successfull (CompileSuccess)
  2. The compile failed (CompileFailure)

Let’s assume the compile was successfull. I have seen two or maybe three ways to handle it:

  1. return new CompileResult( new CompileSuccess("success info") ) where CompileResult contains a CompileSuccess.
  2. return new CompileSuccess("success info") where CompileSuccess implements CompileResult.
  3. CompileResult.from( CompileSuccess("success info") ) which could possibly implemented to return either a CompileResult object or a CompileSuccess object (as in 2.)

Are there other ways to accomplish what I want to do? I saw the 2. “inheritation” way in Google guavas Either and in Scalas Either. In guava the 3. way is used for the Option type. What are the differences and when to choose what?

8

The major issue with your two first solutions is that you couple the compile phase and the creation/instancing of the result. Your third way add a dependency of your class with an unique way to create the result (CompileResult).
Let’s solve the first point (delegating Result creation):

class SuccessDetails {
    private String description;
    public SuccessDetails (String description) {
        this.description = description;
    }
}
class FailureDetails {
    private String description;
    public FailureDetails (String description) {
        this.description = description;
    }
}
class FailResultDetailed extends Result {
    private FailureDetails details;
    public FailResultDetailed (FailureDetails details) { this.details = details; }
}
class SuccessResultDetailed extends Result {
    private SuccessDetails details;
    public SuccessResultDetailed (SuccessDetails details) { this.details = details; }
}
class Result {}
class SuccessResult extends Result {
    private String description;
    public SuccessResult (String description) { this.description = description; }
}
class FailResult extends Result {
    private String description;
    public FailResult (String description) { this.description = description; }
}
interface IResultFactory {
    public SuccessResultDetailed success (SuccessDetails details);
    public FailResultDetailed fail (FailureDetails details);
}
class ResultFactory implements IResultFactory {
    public ResultFactory () { }
    public SuccessResultDetailed success (SuccessDetails details) { return new SuccessResultDetailed(details); }
    public FailResultDetailed fail (FailureDetails details) { return new FailResultDetailed(details); }
}
class Compiler {
    private IResultFactory resultFactory;
    public Compiler (IResultFactory resultFactory) { this.resultFactory = resultFactory; }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.success(new SuccessDetails("Ok"));
        else
            return resultFactory.fail(new FailureDetails("You've made a mistake"));
    }
}

Now your are free to change the way you handle and create the Result object, but you might want to add some details.
The most intuitive way to solve it (for a OO developer) is to extract the details in a bunch of other classes:

class SuccessWithWarningsDetails extends SuccessDetails {
    private int[] lines;
    public SuccessWithWarningsDetails (String description, int[] lines) {
        super(description);
        this.lines = lines;
    }
}
class CompilerThatThrowsWarnings {
    private IResultFactory resultFactory;
    public CompilerThatThrowsWarnings (IResultFactory resultFactory) { this.resultFactory = resultFactory; }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.success(new SuccessWithWarningsDetails("Ok", new int[] {1, 2, 3}));
        else
            return resultFactory.fail(new FailureDetails("You've made a mistake"));
    }
}

But again, we couple the compile phase and the creation/instancing of the result.
We can try to apply the same process we have done the first time:

interface IResultDetailsFactory {
    public SuccessDetails success (String description);
    public SuccessWithWarningsDetails successWithWarnings (String description, int[] lines);
    public FailureDetails failure (String description);
}
class ResultDetailsFactory implements IResultDetailsFactory{
    public ResultDetailsFactory () { }
    public SuccessDetails success (String description) { return new SuccessDetails(description); }
    public SuccessWithWarningsDetails successWithWarnings (String description, int[] lines) { return new SuccessWithWarningsDetails(description, lines); }
    public FailureDetails failure (String description) { return new FailureDetails(description); }
}
class CompilerThatThrowsWarningsWithoutCreation {
    private IResultFactory resultFactory;
    private IResultDetailsFactory resultDetailsFactory;
    public CompilerThatThrowsWarningsWithoutCreation (IResultFactory resultFactory, IResultDetailsFactory resultDetailsFactory) {
        this.resultFactory = resultFactory;
        this.resultDetailsFactory = resultDetailsFactory;
    }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.success(resultDetailsFactory.successWithWarnings("Ok", new int[] {1, 2, 3}));
        else
            return resultFactory.fail(resultDetailsFactory.failure("You've made a mistake"));
    }
}

We are so close to the ending, if only we hadn’t the resultFactory depency…
Why? because we only care about producing Result, not how they are arranged.

interface IResultDetailsAndResultFactory {
    public SuccessResultDetailed success (String description);
    public SuccessResultDetailed successWithWarnings (String description, int[] lines);
    public FailResultDetailed failure (String description);
}
class ResultDetailsAndResultFactory implements IResultDetailsAndResultFactory {
    private IResultFactory resultFactory;
    public ResultDetailsAndResultFactory (IResultFactory resultFactory) { this.resultFactory = resultFactory; }
    public SuccessResultDetailed success (String description) { return resultFactory.success(new SuccessDetails(description)); }
    public SuccessResultDetailed successWithWarnings (String description, int[] lines) { return resultFactory.success(new SuccessWithWarningsDetails(description, lines)); }
    public FailResultDetailed failure (String description) { return resultFactory.fail(new FailureDetails(description)); }
}
class CompilerThatThrowsWarningsWithoutCreationAndResult {
    private IResultDetailsAndResultFactory resultFactory;
    public CompilerThatThrowsWarningsWithoutCreationAndResult  (IResultDetailsAndResultFactory resultFactory) {
        this.resultFactory = resultFactory;
    }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.successWithWarnings("Ok", new int[] {1, 2, 3});
        else
            return resultFactory.failure("You've made a mistake");
    }
}

Now we have not only a Compile phase that only depends on a factory to build detailed Results, but we also have results that only depends on a factory to handle the way they will be processed.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Advantages and drawbacks of different ways using Either-types [closed]

I am writing software for compiling programs. Therefore have a Compiler that compiles a given sourcecode. It then returns a CompileResult that is similiar to an Either type (it is actually internally delegating to an Either object). Now there can be 2 (non-exceptional) cases:

  1. The compile is successfull (CompileSuccess)
  2. The compile failed (CompileFailure)

Let’s assume the compile was successfull. I have seen two or maybe three ways to handle it:

  1. return new CompileResult( new CompileSuccess("success info") ) where CompileResult contains a CompileSuccess.
  2. return new CompileSuccess("success info") where CompileSuccess implements CompileResult.
  3. CompileResult.from( CompileSuccess("success info") ) which could possibly implemented to return either a CompileResult object or a CompileSuccess object (as in 2.)

Are there other ways to accomplish what I want to do? I saw the 2. “inheritation” way in Google guavas Either and in Scalas Either. In guava the 3. way is used for the Option type. What are the differences and when to choose what?

8

The major issue with your two first solutions is that you couple the compile phase and the creation/instancing of the result. Your third way add a dependency of your class with an unique way to create the result (CompileResult).
Let’s solve the first point (delegating Result creation):

class SuccessDetails {
    private String description;
    public SuccessDetails (String description) {
        this.description = description;
    }
}
class FailureDetails {
    private String description;
    public FailureDetails (String description) {
        this.description = description;
    }
}
class FailResultDetailed extends Result {
    private FailureDetails details;
    public FailResultDetailed (FailureDetails details) { this.details = details; }
}
class SuccessResultDetailed extends Result {
    private SuccessDetails details;
    public SuccessResultDetailed (SuccessDetails details) { this.details = details; }
}
class Result {}
class SuccessResult extends Result {
    private String description;
    public SuccessResult (String description) { this.description = description; }
}
class FailResult extends Result {
    private String description;
    public FailResult (String description) { this.description = description; }
}
interface IResultFactory {
    public SuccessResultDetailed success (SuccessDetails details);
    public FailResultDetailed fail (FailureDetails details);
}
class ResultFactory implements IResultFactory {
    public ResultFactory () { }
    public SuccessResultDetailed success (SuccessDetails details) { return new SuccessResultDetailed(details); }
    public FailResultDetailed fail (FailureDetails details) { return new FailResultDetailed(details); }
}
class Compiler {
    private IResultFactory resultFactory;
    public Compiler (IResultFactory resultFactory) { this.resultFactory = resultFactory; }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.success(new SuccessDetails("Ok"));
        else
            return resultFactory.fail(new FailureDetails("You've made a mistake"));
    }
}

Now your are free to change the way you handle and create the Result object, but you might want to add some details.
The most intuitive way to solve it (for a OO developer) is to extract the details in a bunch of other classes:

class SuccessWithWarningsDetails extends SuccessDetails {
    private int[] lines;
    public SuccessWithWarningsDetails (String description, int[] lines) {
        super(description);
        this.lines = lines;
    }
}
class CompilerThatThrowsWarnings {
    private IResultFactory resultFactory;
    public CompilerThatThrowsWarnings (IResultFactory resultFactory) { this.resultFactory = resultFactory; }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.success(new SuccessWithWarningsDetails("Ok", new int[] {1, 2, 3}));
        else
            return resultFactory.fail(new FailureDetails("You've made a mistake"));
    }
}

But again, we couple the compile phase and the creation/instancing of the result.
We can try to apply the same process we have done the first time:

interface IResultDetailsFactory {
    public SuccessDetails success (String description);
    public SuccessWithWarningsDetails successWithWarnings (String description, int[] lines);
    public FailureDetails failure (String description);
}
class ResultDetailsFactory implements IResultDetailsFactory{
    public ResultDetailsFactory () { }
    public SuccessDetails success (String description) { return new SuccessDetails(description); }
    public SuccessWithWarningsDetails successWithWarnings (String description, int[] lines) { return new SuccessWithWarningsDetails(description, lines); }
    public FailureDetails failure (String description) { return new FailureDetails(description); }
}
class CompilerThatThrowsWarningsWithoutCreation {
    private IResultFactory resultFactory;
    private IResultDetailsFactory resultDetailsFactory;
    public CompilerThatThrowsWarningsWithoutCreation (IResultFactory resultFactory, IResultDetailsFactory resultDetailsFactory) {
        this.resultFactory = resultFactory;
        this.resultDetailsFactory = resultDetailsFactory;
    }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.success(resultDetailsFactory.successWithWarnings("Ok", new int[] {1, 2, 3}));
        else
            return resultFactory.fail(resultDetailsFactory.failure("You've made a mistake"));
    }
}

We are so close to the ending, if only we hadn’t the resultFactory depency…
Why? because we only care about producing Result, not how they are arranged.

interface IResultDetailsAndResultFactory {
    public SuccessResultDetailed success (String description);
    public SuccessResultDetailed successWithWarnings (String description, int[] lines);
    public FailResultDetailed failure (String description);
}
class ResultDetailsAndResultFactory implements IResultDetailsAndResultFactory {
    private IResultFactory resultFactory;
    public ResultDetailsAndResultFactory (IResultFactory resultFactory) { this.resultFactory = resultFactory; }
    public SuccessResultDetailed success (String description) { return resultFactory.success(new SuccessDetails(description)); }
    public SuccessResultDetailed successWithWarnings (String description, int[] lines) { return resultFactory.success(new SuccessWithWarningsDetails(description, lines)); }
    public FailResultDetailed failure (String description) { return resultFactory.fail(new FailureDetails(description)); }
}
class CompilerThatThrowsWarningsWithoutCreationAndResult {
    private IResultDetailsAndResultFactory resultFactory;
    public CompilerThatThrowsWarningsWithoutCreationAndResult  (IResultDetailsAndResultFactory resultFactory) {
        this.resultFactory = resultFactory;
    }
    public Result compile (String code, Boolean result) {
        if (result)
            return resultFactory.successWithWarnings("Ok", new int[] {1, 2, 3});
        else
            return resultFactory.failure("You've made a mistake");
    }
}

Now we have not only a Compile phase that only depends on a factory to build detailed Results, but we also have results that only depends on a factory to handle the way they will be processed.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật