Yes Java doesn't the bytecode/JVM does :-). Here is the setup to show it
would break without recompilation downstream:

[john@sentinel:test]% cat Upstream_void.java
> public class Upstream {
>     static void Hello() {
>         System.out.println("Hello (void)!");
>     }
> }
>


> [john@sentinel:test]% cat Upstream_String.java
> public class Upstream {
>     static String Hello() {
>         System.out.println("Hello (String)!");
>         return "Why oh why!?!";
>     }
> }
>


> [john@sentinel:test]% cat Main.java
> public class Main {
>     public static void main(String[] args) {
>         Upstream.Hello();
>     }
> }


We compile/run this like this:

 [john@sentinel:test]% cp Upstream_void.java Upstream.java && javac
> Upstream.java Main.java && java -cp . Main
> Hello (void)!


Now if I try it with Upstream_String instead and *DON'T* recompile
Main.java you should the following error:

 [john@sentinel:test]% cp Upstream_String.java Upstream.java && javac
> Upstream.java && java -cp . Main
> Exception in thread "main" java.lang.NoSuchMethodError: 'void
> Upstream.Hello()'
> at Main.main(Main.java:3)


If you recompile Main.java it's OK again.

[john@sentinel:test]% cp Upstream_String.java Upstream.java && javac
> Upstream.java Main.java && java -cp . Main
> Hello (String)!
>

J

On Mon, 5 Sept 2022 at 15:12, Uli Fechner <u...@pending.ai> wrote:

> To the best of my knowledge the return type is not part of the method
> signature as such in Java.
>
> You might think of covariant return types which come into play when
> overriding a method in a child class, and the child’s return type can be a
> subtype of the parent’s return type. This was introduced in Java 5. If the
> parent's method return type is void, however, you won't be able to change
> the return type of the child's method.
>
> On Tue, Sep 6, 2022 at 12:04 AM John Mayfield <john.wilkinson...@gmail.com>
> wrote:
>
>> I did contemplate making the addAtom() return the new "ref" the container
>> has... however I think this is technically an API breakage (void => IAtom
>> return type). This would not have been in prior Java versions but at some
>> point they added the return type to the signature. It's kind of a minor
>> breakage, basically providing the downstream gets recompiled byte code it's
>> OK.
>>
>> On Mon, 5 Sept 2022 at 14:59, John Mayfield <john.wilkinson...@gmail.com>
>> wrote:
>>
>>> Yup! Sorry just drafting stuff out :-) Made the same mistake in the PR
>>> which used predicates:
>>> https://github.com/cdk/cdk/pull/889/commits/a160def65f79218a410c8fa4fe6ece5e2ed40dde
>>>
>>>
>>> On Mon, 5 Sept 2022 at 14:47, Daniel Katzel <dkat...@gmail.com> wrote:
>>>
>>>> Surely that line output.getAtom( atom.getAtomicNumber() -1 )
>>>>
>>>> Was meant to use output.getAtomCount() -1
>>>>
>>>> To get the last atom added?
>>>>
>>>> On Mon, Sep 5, 2022, 6:44 AM John Mayfield <john.wilkinson...@gmail.com>
>>>> wrote:
>>>>
>>>>> Yes and it's correct, your code is adding bonds to atoms which don't
>>>>> exist yet! You need to add the atoms of the bond before the bond - 0..k 
>>>>> not
>>>>> k .. n.
>>>>>
>>>>> As an aside the Mappings API has this method
>>>>> already (toSubstructureStream()) if you're coming via CDK substructure
>>>>> Pattern (although it doesn't do the radials/lone pairs... possible but I
>>>>> never found a use to have them explicitly like that).
>>>>>
>>>>> In general this code is an inefficient way to build the container... I
>>>>> think it's O(N^3) - but perhaps only O(N^2) with AtomContainer2 :-). Much
>>>>> better to add all the atoms, record these in a set/map, then loop all the
>>>>> bonds. Optionally for best performance you should do this "resync"
>>>>> operation where you map the source => target AtomRef. Maybe we should add
>>>>> this to the ACmanipulator, I thought there was something similar
>>>>> already though.
>>>>>
>>>>> John
>>>>>
>>>>> public static IAtomContainer extractSubstructure(IAtomContainer source, 
>>>>> List<IAtom> atoms) {
>>>>>     IAtomContainer output = source.getBuilder().newAtomContainer();
>>>>>     Map<IAtom,IAtom> remap = new HashMap<>();
>>>>>     for (IAtom atom : atoms) {
>>>>>         output.addAtom(atom);
>>>>>         
>>>>> source.getConnectedLonePairsList(atom).forEach(output::addLonePair);
>>>>>         
>>>>> source.getConnectedSingleElectronsList(atom).forEach(output::addSingleElectron);
>>>>>         // resync: get the AtomRef in the context of the new container. 
>>>>> This
>>>>>         // presumes atoms gets added at last position which is currently
>>>>>         // always the case
>>>>>         remap.put(atom, output.getAtom(atom.getAtomicNumber() - 1));
>>>>>     }
>>>>>     for (IBond bond : source.bonds()) {
>>>>>         IAtom beg = remap.get(bond.getBegin());
>>>>>         IAtom end = remap.get(bond.getEnd());
>>>>>         if (beg != null && end != null) {
>>>>>             output.addBond(bond);
>>>>>
>>>>>             // or the more efficient but you get a "NEW" bond so may need 
>>>>> to some fudging with
>>>>>             // setting aromatcity/ring membership etc, however if you're 
>>>>> selecting a substructure
>>>>>             // you MUST recalculate these anyways.
>>>>>             // output.addBond(beg.getIndex(), end.getIndex(), 
>>>>> bond.getOrder(), bond.getStereo());
>>>>>         }
>>>>>     }
>>>>>     return output;
>>>>> }
>>>>>
>>>>>
>>>>> On Mon, 5 Sept 2022 at 11:10, Uli Fechner <u...@pending.ai> wrote:
>>>>>
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> I get a NoSuchAtomException when executing the following code (that I
>>>>>> inherited):
>>>>>>
>>>>>> public static IAtomContainer extractSubstructure(IAtomContainer source, 
>>>>>> List<IAtom> atoms) {
>>>>>>     IAtomContainer output = 
>>>>>> SilentChemObjectBuilder.getInstance().newAtomContainer();
>>>>>>     int k = 0;
>>>>>>     for (IAtom atom : atoms) {
>>>>>>         output.addAtom(atom);
>>>>>>         source.getConnectedLonePairsList(atom).forEach(lp -> 
>>>>>> output.addLonePair(lp));
>>>>>>         source.getConnectedSingleElectronsList(atom).forEach(se -> 
>>>>>> output.addSingleElectron(se));
>>>>>>         k++;
>>>>>>         for (int i = k; i < atoms.size(); i++) {
>>>>>>             IBond bond = source.getBond(atom, atoms.get(i));
>>>>>>             if (bond != null) {
>>>>>>                 output.addBond(bond);
>>>>>>             }
>>>>>>         }
>>>>>>     }
>>>>>>     return output;
>>>>>> }
>>>>>>
>>>>>> The stack trace starts at the line with
>>>>>> output.addBond(bond);
>>>>>>
>>>>>> and continues with the following lines:
>>>>>>
>>>>>> org.openscience.cdk.exception.NoSuchAtomException: Atom is not a member 
>>>>>> of this AtomContainer
>>>>>>  at 
>>>>>> app//org.openscience.cdk.silent.AtomContainer2.getAtomRef(AtomContainer2.java:185)
>>>>>>  at 
>>>>>> app//org.openscience.cdk.silent.AtomContainer2.newBondRef(AtomContainer2.java:221)
>>>>>>  at 
>>>>>> app//org.openscience.cdk.silent.AtomContainer2.addBond(AtomContainer2.java:908)
>>>>>>
>>>>>> The exception *isn't* thrown if I replace the instantiation of the
>>>>>> IAtomContainer output with
>>>>>> IAtomContainer output = new AtomContainer();
>>>>>> I understand that the exception has something to do with the way
>>>>>> AtomContainer2 is implemented, but I don't know how to switch to the
>>>>>> AtomContainer2 implementation and still retain the intent of the code -
>>>>>> which is to only add atoms, their connected LPs, their connected single
>>>>>> electrons and their connected bonds, but not connected atoms - to the
>>>>>> returned subgraph. Best
>>>>>> Uli
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> Cdk-user mailing list
>>>>>> Cdk-user@lists.sourceforge.net
>>>>>> https://lists.sourceforge.net/lists/listinfo/cdk-user
>>>>>>
>>>>> _______________________________________________
>>>>> Cdk-user mailing list
>>>>> Cdk-user@lists.sourceforge.net
>>>>> https://lists.sourceforge.net/lists/listinfo/cdk-user
>>>>>
>>>>
_______________________________________________
Cdk-user mailing list
Cdk-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/cdk-user

Reply via email to