EphemeralConst.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-7.1.0).
003  * Copyright (c) 2007-2022 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.prog.op;
021 
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 import static io.jenetics.internal.util.SerialIO.readNullableString;
025 import static io.jenetics.internal.util.SerialIO.writeNullableString;
026 
027 import java.io.IOException;
028 import java.io.InvalidObjectException;
029 import java.io.ObjectInput;
030 import java.io.ObjectInputStream;
031 import java.io.ObjectOutput;
032 import java.io.Serial;
033 import java.io.Serializable;
034 import java.util.Objects;
035 import java.util.function.Supplier;
036 
037 import io.jenetics.internal.util.Lazy;
038 
039 /**
040  * Implementation of an <em>ephemeral</em> constant. It causes the insertion of
041  * a <em>mutable</em> constant into the operation tree. Every time this terminal
042  * is chosen a, different value is generated which is then used for that
043  * particular terminal, and which will remain fixed for the given tree. The main
044  * usage would be to introduce random terminal values.
045  *
046  <pre>{@code
047  * final Random random = ...;
048  * final Op<Double> val = EphemeralConst.of(random::nextDouble);
049  * }</pre>
050  *
051  <b>Serialization</b>
052  * Although the {@code EphemeralConst} class implements the {@link Serializable}
053  * interface, the serialization will fail if the <em>const</em> supplier is not
054  <em>serializable</em> as well. This can be achieved by <em>casting</em> the
055  * supplier to a {@link Serializable}.
056  <pre>{@code
057  * final Random random = new Random();
058  * final EphemeralConst<Integer> object = EphemeralConst.of(
059  *     "R",
060  *     (Supplier<Integer> & Serializable)random::nextInt
061  * );
062  * }</pre>
063  * The serialization of the <em>constant</em> will fail, if the lambda has to
064  * capture variables form a <em>non</em>-serializable context (class). In such a
065  * case it is advisable to create a dedicated supplier class.
066  <pre>{@code
067  * final class RandomInt implements Supplier<Integer>, Serializable {
068  *     private final Random rnd = new Random();
069  *     private final int min;
070  *     private final int max;
071  *
072  *     private RandomInt(final int min, final int max) {
073  *         this.min = min;
074  *         this.max = max;
075  *     }
076  *
077  *     \@Override
078  *     public Integer get() {
079  *         return rnd.nextInt(max - min) + min;
080  *     }
081  * }
082  * }</pre>
083  *
084  *
085  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
086  @version 7.0
087  @since 3.9
088  */
089 public final class EphemeralConst<T>
090     extends Val<T>
091     implements Op<T>, Serializable
092 {
093 
094     @Serial
095     private static final long serialVersionUID = 1L;
096 
097     private final Lazy<T> _value;
098     private final Supplier<T> _supplier;
099 
100     private EphemeralConst(
101         final String name,
102         final Lazy<T> value,
103         final Supplier<T> supplier
104     ) {
105         super(name);
106         _value = requireNonNull(value);
107         _supplier = requireNonNull(supplier);
108     }
109 
110     private EphemeralConst(final String name, final Supplier<T> supplier) {
111         this(name, Lazy.of(supplier), supplier);
112     }
113 
114     /**
115      * Return a newly created, uninitialized constant of type {@code T}.
116      *
117      @return a newly created, uninitialized constant of type {@code T}
118      */
119     @Override
120     public Op<T> get() {
121         return new EphemeralConst<>(name(), _supplier);
122     }
123 
124     /**
125      * Fixes and returns the constant value.
126      *
127      @since 5.0
128      *
129      @return the constant value
130      */
131     @Override
132     public T value() {
133         return _value.get();
134     }
135 
136     @Override
137     public String toString() {
138         return name() != null
139             ? format("%s(%s)", name(), value())
140             : Objects.toString(value());
141     }
142 
143     /**
144      * Create a new ephemeral constant with the given {@code name} and value
145      * {@code supplier}. For every newly created operation tree, a new constant
146      * value is chosen for this terminal operation. The value is than kept
147      * constant for this tree.
148      *
149      @param name the name of the ephemeral constant
150      @param supplier the value supplier
151      @param <T> the constant type
152      @return a new ephemeral constant
153      @throws NullPointerException if one of the arguments is {@code null}
154      */
155     public static <T> EphemeralConst<T> of(
156         final String name,
157         final Supplier<T> supplier
158     ) {
159         return new EphemeralConst<>(requireNonNull(name), supplier);
160     }
161 
162     /**
163      * Create a new ephemeral constant with the given value {@code supplier}.
164      * For every newly created operation tree, a new constant value is chosen
165      * for this terminal operation. The value is than kept constant for this tree.
166      *
167      @param supplier the value supplier
168      @param <T> the constant type
169      @return a new ephemeral constant
170      @throws NullPointerException if the {@code supplier} is {@code null}
171      */
172     public static <T> EphemeralConst<T> of(final Supplier<T> supplier) {
173         return new EphemeralConst<>(null, supplier);
174     }
175 
176 
177     /* *************************************************************************
178      *  Java object serialization
179      * ************************************************************************/
180 
181     @Serial
182     private Object writeReplace() {
183         return new SerialProxy(SerialProxy.EPHEMERAL_CONST, this);
184     }
185 
186     @Serial
187     private void readObject(final ObjectInputStream stream)
188         throws InvalidObjectException
189     {
190         throw new InvalidObjectException("Serialization proxy required.");
191     }
192 
193     void write(final ObjectOutput outthrows IOException {
194         writeNullableString(name(), out);
195         out.writeObject(value());
196         out.writeObject(_supplier);
197     }
198 
199     @SuppressWarnings({"unchecked""rawtypes"})
200     static EphemeralConst read(final ObjectInput in)
201         throws IOException, ClassNotFoundException
202     {
203         final String name = readNullableString(in);
204         final Object value = in.readObject();
205         final Supplier supplier = (Supplier)in.readObject();
206 
207         return new EphemeralConst(name, Lazy.ofValue(value), supplier);
208     }
209 
210 }